Bez popisu

server.js 36KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. /**
  2. * Satellizer Node.js Example
  3. * (c) 2015 Sahat Yalkabov
  4. * License: MIT
  5. */
  6. var path = require('path');
  7. var qs = require('querystring');
  8. var async = require('async');
  9. var bcrypt = require('bcryptjs');
  10. var bodyParser = require('body-parser');
  11. var colors = require('colors');
  12. var cors = require('cors');
  13. var express = require('express');
  14. var logger = require('morgan');
  15. var jwt = require('jwt-simple');
  16. var moment = require('moment');
  17. var mongoose = require('mongoose');
  18. var request = require('request');
  19. var config = require('./config');
  20. var userSchema = new mongoose.Schema({
  21. email: { type: String, unique: true, lowercase: true },
  22. password: { type: String, select: false },
  23. displayName: String,
  24. picture: String,
  25. bitbucket: String,
  26. facebook: String,
  27. foursquare: String,
  28. google: String,
  29. github: String,
  30. instagram: String,
  31. linkedin: String,
  32. live: String,
  33. yahoo: String,
  34. twitter: String,
  35. twitch: String
  36. });
  37. userSchema.pre('save', function(next) {
  38. var user = this;
  39. if (!user.isModified('password')) {
  40. return next();
  41. }
  42. bcrypt.genSalt(10, function(err, salt) {
  43. bcrypt.hash(user.password, salt, function(err, hash) {
  44. user.password = hash;
  45. next();
  46. });
  47. });
  48. });
  49. userSchema.methods.comparePassword = function(password, done) {
  50. bcrypt.compare(password, this.password, function(err, isMatch) {
  51. done(err, isMatch);
  52. });
  53. };
  54. var User = mongoose.model('User', userSchema);
  55. mongoose.connect(config.MONGO_URI);
  56. mongoose.connection.on('error', function(err) {
  57. console.log('Error: Could not connect to MongoDB. Did you forget to run `mongod`?'.red);
  58. });
  59. var app = express();
  60. app.set('port', process.env.NODE_PORT || 3000);
  61. app.set('host', process.env.NODE_IP || 'localhost');
  62. app.use(cors());
  63. app.use(logger('dev'));
  64. app.use(bodyParser.json());
  65. app.use(bodyParser.urlencoded({ extended: true }));
  66. // Force HTTPS on Heroku
  67. if (app.get('env') === 'production') {
  68. app.use(function(req, res, next) {
  69. var protocol = req.get('x-forwarded-proto');
  70. protocol == 'https' ? next() : res.redirect('https://' + req.hostname + req.url);
  71. });
  72. }
  73. app.use(express.static(path.join(__dirname, '../../client')));
  74. /*
  75. |--------------------------------------------------------------------------
  76. | Login Required Middleware
  77. |--------------------------------------------------------------------------
  78. */
  79. function ensureAuthenticated(req, res, next) {
  80. if (!req.header('Authorization')) {
  81. return res.status(401).send({ message: 'Please make sure your request has an Authorization header' });
  82. }
  83. var token = req.header('Authorization').split(' ')[1];
  84. var payload = null;
  85. try {
  86. payload = jwt.decode(token, config.TOKEN_SECRET);
  87. }
  88. catch (err) {
  89. return res.status(401).send({ message: err.message });
  90. }
  91. if (payload.exp <= moment().unix()) {
  92. return res.status(401).send({ message: 'Token has expired' });
  93. }
  94. req.user = payload.sub;
  95. next();
  96. }
  97. /*
  98. |--------------------------------------------------------------------------
  99. | Generate JSON Web Token
  100. |--------------------------------------------------------------------------
  101. */
  102. function createJWT(user) {
  103. var payload = {
  104. sub: user._id,
  105. iat: moment().unix(),
  106. exp: moment().add(14, 'days').unix()
  107. };
  108. return jwt.encode(payload, config.TOKEN_SECRET);
  109. }
  110. /*
  111. |--------------------------------------------------------------------------
  112. | GET /api/me
  113. |--------------------------------------------------------------------------
  114. */
  115. app.get('/api/me', ensureAuthenticated, function(req, res) {
  116. User.findById(req.user, function(err, user) {
  117. res.send(user);
  118. });
  119. });
  120. /*
  121. |--------------------------------------------------------------------------
  122. | PUT /api/me
  123. |--------------------------------------------------------------------------
  124. */
  125. app.put('/api/me', ensureAuthenticated, function(req, res) {
  126. User.findById(req.user, function(err, user) {
  127. if (!user) {
  128. return res.status(400).send({ message: 'User not found' });
  129. }
  130. user.displayName = req.body.displayName || user.displayName;
  131. user.email = req.body.email || user.email;
  132. user.save(function(err) {
  133. res.status(200).end();
  134. });
  135. });
  136. });
  137. /*
  138. |--------------------------------------------------------------------------
  139. | Log in with Email
  140. |--------------------------------------------------------------------------
  141. */
  142. app.post('/auth/login', function(req, res) {
  143. User.findOne({ email: req.body.email }, '+password', function(err, user) {
  144. if (!user) {
  145. return res.status(401).send({ message: 'Invalid email and/or password' });
  146. }
  147. user.comparePassword(req.body.password, function(err, isMatch) {
  148. if (!isMatch) {
  149. return res.status(401).send({ message: 'Invalid email and/or password' });
  150. }
  151. res.send({ token: createJWT(user) });
  152. });
  153. });
  154. });
  155. /*
  156. |--------------------------------------------------------------------------
  157. | Create Email and Password Account
  158. |--------------------------------------------------------------------------
  159. */
  160. app.post('/auth/signup', function(req, res) {
  161. User.findOne({ email: req.body.email }, function(err, existingUser) {
  162. if (existingUser) {
  163. return res.status(409).send({ message: 'Email is already taken' });
  164. }
  165. var user = new User({
  166. displayName: req.body.displayName,
  167. email: req.body.email,
  168. password: req.body.password
  169. });
  170. user.save(function(err, result) {
  171. if (err) {
  172. res.status(500).send({ message: err.message });
  173. }
  174. res.send({ token: createJWT(result) });
  175. });
  176. });
  177. });
  178. /*
  179. |--------------------------------------------------------------------------
  180. | Login with Google
  181. |--------------------------------------------------------------------------
  182. */
  183. app.post('/auth/google', function(req, res) {
  184. var accessTokenUrl = 'https://accounts.google.com/o/oauth2/token';
  185. var peopleApiUrl = 'https://www.googleapis.com/plus/v1/people/me/openIdConnect';
  186. var params = {
  187. code: req.body.code,
  188. client_id: req.body.clientId,
  189. client_secret: config.GOOGLE_SECRET,
  190. redirect_uri: req.body.redirectUri,
  191. grant_type: 'authorization_code'
  192. };
  193. // Step 1. Exchange authorization code for access token.
  194. request.post(accessTokenUrl, { json: true, form: params }, function(err, response, token) {
  195. var accessToken = token.access_token;
  196. var headers = { Authorization: 'Bearer ' + accessToken };
  197. // Step 2. Retrieve profile information about the current user.
  198. request.get({ url: peopleApiUrl, headers: headers, json: true }, function(err, response, profile) {
  199. if (profile.error) {
  200. return res.status(500).send({message: profile.error.message});
  201. }
  202. // Step 3a. Link user accounts.
  203. if (req.header('Authorization')) {
  204. User.findOne({ google: profile.sub }, function(err, existingUser) {
  205. if (existingUser) {
  206. return res.status(409).send({ message: 'There is already a Google account that belongs to you' });
  207. }
  208. var token = req.header('Authorization').split(' ')[1];
  209. var payload = jwt.decode(token, config.TOKEN_SECRET);
  210. User.findById(payload.sub, function(err, user) {
  211. if (!user) {
  212. return res.status(400).send({ message: 'User not found' });
  213. }
  214. user.google = profile.sub;
  215. user.picture = user.picture || profile.picture.replace('sz=50', 'sz=200');
  216. user.displayName = user.displayName || profile.name;
  217. user.save(function() {
  218. var token = createJWT(user);
  219. res.send({ token: token });
  220. });
  221. });
  222. });
  223. } else {
  224. // Step 3b. Create a new user account or return an existing one.
  225. User.findOne({ google: profile.sub }, function(err, existingUser) {
  226. if (existingUser) {
  227. return res.send({ token: createJWT(existingUser) });
  228. }
  229. var user = new User();
  230. user.google = profile.sub;
  231. user.picture = profile.picture.replace('sz=50', 'sz=200');
  232. user.displayName = profile.name;
  233. user.save(function(err) {
  234. var token = createJWT(user);
  235. res.send({ token: token });
  236. });
  237. });
  238. }
  239. });
  240. });
  241. });
  242. /*
  243. |--------------------------------------------------------------------------
  244. | Login with GitHub
  245. |--------------------------------------------------------------------------
  246. */
  247. app.post('/auth/github', function(req, res) {
  248. var accessTokenUrl = 'https://github.com/login/oauth/access_token';
  249. var userApiUrl = 'https://api.github.com/user';
  250. var params = {
  251. code: req.body.code,
  252. client_id: req.body.clientId,
  253. client_secret: config.GITHUB_SECRET,
  254. redirect_uri: req.body.redirectUri
  255. };
  256. // Step 1. Exchange authorization code for access token.
  257. request.get({ url: accessTokenUrl, qs: params }, function(err, response, accessToken) {
  258. accessToken = qs.parse(accessToken);
  259. var headers = { 'User-Agent': 'Satellizer' };
  260. // Step 2. Retrieve profile information about the current user.
  261. request.get({ url: userApiUrl, qs: accessToken, headers: headers, json: true }, function(err, response, profile) {
  262. // Step 3a. Link user accounts.
  263. if (req.header('Authorization')) {
  264. User.findOne({ github: profile.id }, function(err, existingUser) {
  265. if (existingUser) {
  266. return res.status(409).send({ message: 'There is already a GitHub account that belongs to you' });
  267. }
  268. var token = req.header('Authorization').split(' ')[1];
  269. var payload = jwt.decode(token, config.TOKEN_SECRET);
  270. User.findById(payload.sub, function(err, user) {
  271. if (!user) {
  272. return res.status(400).send({ message: 'User not found' });
  273. }
  274. user.github = profile.id;
  275. user.picture = user.picture || profile.avatar_url;
  276. user.displayName = user.displayName || profile.name;
  277. user.save(function() {
  278. var token = createJWT(user);
  279. res.send({ token: token });
  280. });
  281. });
  282. });
  283. } else {
  284. // Step 3b. Create a new user account or return an existing one.
  285. User.findOne({ github: profile.id }, function(err, existingUser) {
  286. if (existingUser) {
  287. var token = createJWT(existingUser);
  288. return res.send({ token: token });
  289. }
  290. var user = new User();
  291. user.github = profile.id;
  292. user.picture = profile.avatar_url;
  293. user.displayName = profile.name;
  294. user.save(function() {
  295. var token = createJWT(user);
  296. res.send({ token: token });
  297. });
  298. });
  299. }
  300. });
  301. });
  302. });
  303. /*
  304. |--------------------------------------------------------------------------
  305. | Login with Instagram
  306. |--------------------------------------------------------------------------
  307. */
  308. app.post('/auth/instagram', function(req, res) {
  309. var accessTokenUrl = 'https://api.instagram.com/oauth/access_token';
  310. var params = {
  311. client_id: req.body.clientId,
  312. redirect_uri: req.body.redirectUri,
  313. client_secret: config.INSTAGRAM_SECRET,
  314. code: req.body.code,
  315. grant_type: 'authorization_code'
  316. };
  317. // Step 1. Exchange authorization code for access token.
  318. request.post({ url: accessTokenUrl, form: params, json: true }, function(error, response, body) {
  319. // Step 2a. Link user accounts.
  320. if (req.header('Authorization')) {
  321. User.findOne({ instagram: body.user.id }, function(err, existingUser) {
  322. if (existingUser) {
  323. return res.status(409).send({ message: 'There is already an Instagram account that belongs to you' });
  324. }
  325. var token = req.header('Authorization').split(' ')[1];
  326. var payload = jwt.decode(token, config.TOKEN_SECRET);
  327. User.findById(payload.sub, function(err, user) {
  328. if (!user) {
  329. return res.status(400).send({ message: 'User not found' });
  330. }
  331. user.instagram = body.user.id;
  332. user.picture = user.picture || body.user.profile_picture;
  333. user.displayName = user.displayName || body.user.username;
  334. user.save(function() {
  335. var token = createJWT(user);
  336. res.send({ token: token });
  337. });
  338. });
  339. });
  340. } else {
  341. // Step 2b. Create a new user account or return an existing one.
  342. User.findOne({ instagram: body.user.id }, function(err, existingUser) {
  343. if (existingUser) {
  344. return res.send({ token: createJWT(existingUser) });
  345. }
  346. var user = new User({
  347. instagram: body.user.id,
  348. picture: body.user.profile_picture,
  349. displayName: body.user.username
  350. });
  351. user.save(function() {
  352. var token = createJWT(user);
  353. res.send({ token: token, user: user });
  354. });
  355. });
  356. }
  357. });
  358. });
  359. /*
  360. |--------------------------------------------------------------------------
  361. | Login with LinkedIn
  362. |--------------------------------------------------------------------------
  363. */
  364. app.post('/auth/linkedin', function(req, res) {
  365. var accessTokenUrl = 'https://www.linkedin.com/uas/oauth2/accessToken';
  366. var peopleApiUrl = 'https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,picture-url)';
  367. var params = {
  368. code: req.body.code,
  369. client_id: req.body.clientId,
  370. client_secret: config.LINKEDIN_SECRET,
  371. redirect_uri: req.body.redirectUri,
  372. grant_type: 'authorization_code'
  373. };
  374. // Step 1. Exchange authorization code for access token.
  375. request.post(accessTokenUrl, { form: params, json: true }, function(err, response, body) {
  376. if (response.statusCode !== 200) {
  377. return res.status(response.statusCode).send({ message: body.error_description });
  378. }
  379. var params = {
  380. oauth2_access_token: body.access_token,
  381. format: 'json'
  382. };
  383. // Step 2. Retrieve profile information about the current user.
  384. request.get({ url: peopleApiUrl, qs: params, json: true }, function(err, response, profile) {
  385. // Step 3a. Link user accounts.
  386. if (req.header('Authorization')) {
  387. User.findOne({ linkedin: profile.id }, function(err, existingUser) {
  388. if (existingUser) {
  389. return res.status(409).send({ message: 'There is already a LinkedIn account that belongs to you' });
  390. }
  391. var token = req.header('Authorization').split(' ')[1];
  392. var payload = jwt.decode(token, config.TOKEN_SECRET);
  393. User.findById(payload.sub, function(err, user) {
  394. if (!user) {
  395. return res.status(400).send({ message: 'User not found' });
  396. }
  397. user.linkedin = profile.id;
  398. user.picture = user.picture || profile.pictureUrl;
  399. user.displayName = user.displayName || profile.firstName + ' ' + profile.lastName;
  400. user.save(function() {
  401. var token = createJWT(user);
  402. res.send({ token: token });
  403. });
  404. });
  405. });
  406. } else {
  407. // Step 3b. Create a new user account or return an existing one.
  408. User.findOne({ linkedin: profile.id }, function(err, existingUser) {
  409. if (existingUser) {
  410. return res.send({ token: createJWT(existingUser) });
  411. }
  412. var user = new User();
  413. user.linkedin = profile.id;
  414. user.picture = profile.pictureUrl;
  415. user.displayName = profile.firstName + ' ' + profile.lastName;
  416. user.save(function() {
  417. var token = createJWT(user);
  418. res.send({ token: token });
  419. });
  420. });
  421. }
  422. });
  423. });
  424. });
  425. /*
  426. |--------------------------------------------------------------------------
  427. | Login with Windows Live
  428. |--------------------------------------------------------------------------
  429. */
  430. app.post('/auth/live', function(req, res) {
  431. async.waterfall([
  432. // Step 1. Exchange authorization code for access token.
  433. function(done) {
  434. var accessTokenUrl = 'https://login.live.com/oauth20_token.srf';
  435. var params = {
  436. code: req.body.code,
  437. client_id: req.body.clientId,
  438. client_secret: config.WINDOWS_LIVE_SECRET,
  439. redirect_uri: req.body.redirectUri,
  440. grant_type: 'authorization_code'
  441. };
  442. request.post(accessTokenUrl, { form: params, json: true }, function(err, response, accessToken) {
  443. done(null, accessToken);
  444. });
  445. },
  446. // Step 2. Retrieve profile information about the current user.
  447. function(accessToken, done) {
  448. var profileUrl = 'https://apis.live.net/v5.0/me?access_token=' + accessToken.access_token;
  449. request.get({ url: profileUrl, json: true }, function(err, response, profile) {
  450. done(err, profile);
  451. });
  452. },
  453. function(profile) {
  454. // Step 3a. Link user accounts.
  455. if (req.header('Authorization')) {
  456. User.findOne({ live: profile.id }, function(err, user) {
  457. if (user) {
  458. return res.status(409).send({ message: 'There is already a Windows Live account that belongs to you' });
  459. }
  460. var token = req.header('Authorization').split(' ')[1];
  461. var payload = jwt.decode(token, config.TOKEN_SECRET);
  462. User.findById(payload.sub, function(err, existingUser) {
  463. if (!existingUser) {
  464. return res.status(400).send({ message: 'User not found' });
  465. }
  466. existingUser.live = profile.id;
  467. existingUser.displayName = existingUser.displayName || profile.name;
  468. existingUser.save(function() {
  469. var token = createJWT(existingUser);
  470. res.send({ token: token });
  471. });
  472. });
  473. });
  474. } else {
  475. // Step 3b. Create a new user or return an existing account.
  476. User.findOne({ live: profile.id }, function(err, user) {
  477. if (user) {
  478. return res.send({ token: createJWT(user) });
  479. }
  480. var newUser = new User();
  481. newUser.live = profile.id;
  482. newUser.displayName = profile.name;
  483. newUser.save(function() {
  484. var token = createJWT(newUser);
  485. res.send({ token: token });
  486. });
  487. });
  488. }
  489. }
  490. ]);
  491. });
  492. /*
  493. |--------------------------------------------------------------------------
  494. | Login with Facebook
  495. |--------------------------------------------------------------------------
  496. */
  497. app.post('/auth/facebook', function(req, res) {
  498. var fields = ['id', 'email', 'first_name', 'last_name', 'link', 'name'];
  499. var accessTokenUrl = 'https://graph.facebook.com/v2.5/oauth/access_token';
  500. var graphApiUrl = 'https://graph.facebook.com/v2.5/me?fields=' + fields.join(',');
  501. var params = {
  502. code: req.body.code,
  503. client_id: req.body.clientId,
  504. client_secret: config.FACEBOOK_SECRET,
  505. redirect_uri: req.body.redirectUri
  506. };
  507. // Step 1. Exchange authorization code for access token.
  508. request.get({ url: accessTokenUrl, qs: params, json: true }, function(err, response, accessToken) {
  509. if (response.statusCode !== 200) {
  510. return res.status(500).send({ message: accessToken.error.message });
  511. }
  512. // Step 2. Retrieve profile information about the current user.
  513. request.get({ url: graphApiUrl, qs: accessToken, json: true }, function(err, response, profile) {
  514. if (response.statusCode !== 200) {
  515. return res.status(500).send({ message: profile.error.message });
  516. }
  517. if (req.header('Authorization')) {
  518. User.findOne({ facebook: profile.id }, function(err, existingUser) {
  519. if (existingUser) {
  520. return res.status(409).send({ message: 'There is already a Facebook account that belongs to you' });
  521. }
  522. var token = req.header('Authorization').split(' ')[1];
  523. var payload = jwt.decode(token, config.TOKEN_SECRET);
  524. User.findById(payload.sub, function(err, user) {
  525. if (!user) {
  526. return res.status(400).send({ message: 'User not found' });
  527. }
  528. user.facebook = profile.id;
  529. user.picture = user.picture || 'https://graph.facebook.com/v2.3/' + profile.id + '/picture?type=large';
  530. user.displayName = user.displayName || profile.name;
  531. user.save(function() {
  532. var token = createJWT(user);
  533. res.send({ token: token });
  534. });
  535. });
  536. });
  537. } else {
  538. // Step 3. Create a new user account or return an existing one.
  539. User.findOne({ facebook: profile.id }, function(err, existingUser) {
  540. if (existingUser) {
  541. var token = createJWT(existingUser);
  542. return res.send({ token: token });
  543. }
  544. var user = new User();
  545. user.facebook = profile.id;
  546. user.picture = 'https://graph.facebook.com/' + profile.id + '/picture?type=large';
  547. user.displayName = profile.name;
  548. user.save(function() {
  549. var token = createJWT(user);
  550. res.send({ token: token });
  551. });
  552. });
  553. }
  554. });
  555. });
  556. });
  557. /*
  558. |--------------------------------------------------------------------------
  559. | Login with Yahoo
  560. |--------------------------------------------------------------------------
  561. */
  562. app.post('/auth/yahoo', function(req, res) {
  563. var accessTokenUrl = 'https://api.login.yahoo.com/oauth2/get_token';
  564. var clientId = req.body.clientId;
  565. var clientSecret = config.YAHOO_SECRET;
  566. var formData = {
  567. code: req.body.code,
  568. redirect_uri: req.body.redirectUri,
  569. grant_type: 'authorization_code'
  570. };
  571. var headers = { Authorization: 'Basic ' + new Buffer(clientId + ':' + clientSecret).toString('base64') };
  572. // Step 1. Exchange authorization code for access token.
  573. request.post({ url: accessTokenUrl, form: formData, headers: headers, json: true }, function(err, response, body) {
  574. var socialApiUrl = 'https://social.yahooapis.com/v1/user/' + body.xoauth_yahoo_guid + '/profile?format=json';
  575. var headers = { Authorization: 'Bearer ' + body.access_token };
  576. // Step 2. Retrieve profile information about the current user.
  577. request.get({ url: socialApiUrl, headers: headers, json: true }, function(err, response, body) {
  578. // Step 3a. Link user accounts.
  579. if (req.header('Authorization')) {
  580. User.findOne({ yahoo: body.profile.guid }, function(err, existingUser) {
  581. if (existingUser) {
  582. return res.status(409).send({ message: 'There is already a Yahoo account that belongs to you' });
  583. }
  584. var token = req.header('Authorization').split(' ')[1];
  585. var payload = jwt.decode(token, config.TOKEN_SECRET);
  586. User.findById(payload.sub, function(err, user) {
  587. if (!user) {
  588. return res.status(400).send({ message: 'User not found' });
  589. }
  590. user.yahoo = body.profile.guid;
  591. user.displayName = user.displayName || body.profile.nickname;
  592. user.save(function() {
  593. var token = createJWT(user);
  594. res.send({ token: token });
  595. });
  596. });
  597. });
  598. } else {
  599. // Step 3b. Create a new user account or return an existing one.
  600. User.findOne({ yahoo: body.profile.guid }, function(err, existingUser) {
  601. if (existingUser) {
  602. return res.send({ token: createJWT(existingUser) });
  603. }
  604. var user = new User();
  605. user.yahoo = body.profile.guid;
  606. user.displayName = body.profile.nickname;
  607. user.save(function() {
  608. var token = createJWT(user);
  609. res.send({ token: token });
  610. });
  611. });
  612. }
  613. });
  614. });
  615. });
  616. /*
  617. |--------------------------------------------------------------------------
  618. | Login with Twitter
  619. |--------------------------------------------------------------------------
  620. */
  621. app.post('/auth/twitter', function(req, res) {
  622. var requestTokenUrl = 'https://api.twitter.com/oauth/request_token';
  623. var accessTokenUrl = 'https://api.twitter.com/oauth/access_token';
  624. var profileUrl = 'https://api.twitter.com/1.1/users/show.json?screen_name=';
  625. // Part 1 of 2: Initial request from Satellizer.
  626. if (!req.body.oauth_token || !req.body.oauth_verifier) {
  627. var requestTokenOauth = {
  628. consumer_key: config.TWITTER_KEY,
  629. consumer_secret: config.TWITTER_SECRET,
  630. callback: req.body.redirectUri
  631. };
  632. // Step 1. Obtain request token for the authorization popup.
  633. request.post({ url: requestTokenUrl, oauth: requestTokenOauth }, function(err, response, body) {
  634. var oauthToken = qs.parse(body);
  635. // Step 2. Send OAuth token back to open the authorization screen.
  636. res.send(oauthToken);
  637. });
  638. } else {
  639. // Part 2 of 2: Second request after Authorize app is clicked.
  640. var accessTokenOauth = {
  641. consumer_key: config.TWITTER_KEY,
  642. consumer_secret: config.TWITTER_SECRET,
  643. token: req.body.oauth_token,
  644. verifier: req.body.oauth_verifier
  645. };
  646. // Step 3. Exchange oauth token and oauth verifier for access token.
  647. request.post({ url: accessTokenUrl, oauth: accessTokenOauth }, function(err, response, accessToken) {
  648. accessToken = qs.parse(accessToken);
  649. var profileOauth = {
  650. consumer_key: config.TWITTER_KEY,
  651. consumer_secret: config.TWITTER_SECRET,
  652. oauth_token: accessToken.oauth_token
  653. };
  654. // Step 4. Retrieve profile information about the current user.
  655. request.get({
  656. url: profileUrl + accessToken.screen_name,
  657. oauth: profileOauth,
  658. json: true
  659. }, function(err, response, profile) {
  660. // Step 5a. Link user accounts.
  661. if (req.header('Authorization')) {
  662. User.findOne({ twitter: profile.id }, function(err, existingUser) {
  663. if (existingUser) {
  664. return res.status(409).send({ message: 'There is already a Twitter account that belongs to you' });
  665. }
  666. var token = req.header('Authorization').split(' ')[1];
  667. var payload = jwt.decode(token, config.TOKEN_SECRET);
  668. User.findById(payload.sub, function(err, user) {
  669. if (!user) {
  670. return res.status(400).send({ message: 'User not found' });
  671. }
  672. user.twitter = profile.id;
  673. user.displayName = user.displayName || profile.name;
  674. user.picture = user.picture || profile.profile_image_url.replace('_normal', '');
  675. user.save(function(err) {
  676. res.send({ token: createJWT(user) });
  677. });
  678. });
  679. });
  680. } else {
  681. // Step 5b. Create a new user account or return an existing one.
  682. User.findOne({ twitter: profile.id }, function(err, existingUser) {
  683. if (existingUser) {
  684. return res.send({ token: createJWT(existingUser) });
  685. }
  686. var user = new User();
  687. user.twitter = profile.id;
  688. user.displayName = profile.name;
  689. user.picture = profile.profile_image_url.replace('_normal', '');
  690. user.save(function() {
  691. res.send({ token: createJWT(user) });
  692. });
  693. });
  694. }
  695. });
  696. });
  697. }
  698. });
  699. /*
  700. |--------------------------------------------------------------------------
  701. | Login with Foursquare
  702. |--------------------------------------------------------------------------
  703. */
  704. app.post('/auth/foursquare', function(req, res) {
  705. var accessTokenUrl = 'https://foursquare.com/oauth2/access_token';
  706. var profileUrl = 'https://api.foursquare.com/v2/users/self';
  707. var formData = {
  708. code: req.body.code,
  709. client_id: req.body.clientId,
  710. client_secret: config.FOURSQUARE_SECRET,
  711. redirect_uri: req.body.redirectUri,
  712. grant_type: 'authorization_code'
  713. };
  714. // Step 1. Exchange authorization code for access token.
  715. request.post({ url: accessTokenUrl, form: formData, json: true }, function(err, response, body) {
  716. var params = {
  717. v: '20140806',
  718. oauth_token: body.access_token
  719. };
  720. // Step 2. Retrieve information about the current user.
  721. request.get({ url: profileUrl, qs: params, json: true }, function(err, response, profile) {
  722. profile = profile.response.user;
  723. // Step 3a. Link user accounts.
  724. if (req.header('Authorization')) {
  725. User.findOne({ foursquare: profile.id }, function(err, existingUser) {
  726. if (existingUser) {
  727. return res.status(409).send({ message: 'There is already a Foursquare account that belongs to you' });
  728. }
  729. var token = req.header('Authorization').split(' ')[1];
  730. var payload = jwt.decode(token, config.TOKEN_SECRET);
  731. User.findById(payload.sub, function(err, user) {
  732. if (!user) {
  733. return res.status(400).send({ message: 'User not found' });
  734. }
  735. user.foursquare = profile.id;
  736. user.picture = user.picture || profile.photo.prefix + '300x300' + profile.photo.suffix;
  737. user.displayName = user.displayName || profile.firstName + ' ' + profile.lastName;
  738. user.save(function() {
  739. var token = createJWT(user);
  740. res.send({ token: token });
  741. });
  742. });
  743. });
  744. } else {
  745. // Step 3b. Create a new user account or return an existing one.
  746. User.findOne({ foursquare: profile.id }, function(err, existingUser) {
  747. if (existingUser) {
  748. var token = createJWT(existingUser);
  749. return res.send({ token: token });
  750. }
  751. var user = new User();
  752. user.foursquare = profile.id;
  753. user.picture = profile.photo.prefix + '300x300' + profile.photo.suffix;
  754. user.displayName = profile.firstName + ' ' + profile.lastName;
  755. user.save(function() {
  756. var token = createJWT(user);
  757. res.send({ token: token });
  758. });
  759. });
  760. }
  761. });
  762. });
  763. });
  764. /*
  765. |--------------------------------------------------------------------------
  766. | Login with Twitch
  767. |--------------------------------------------------------------------------
  768. */
  769. app.post('/auth/twitch', function(req, res) {
  770. var accessTokenUrl = 'https://api.twitch.tv/kraken/oauth2/token';
  771. var profileUrl = 'https://api.twitch.tv/kraken/user';
  772. var formData = {
  773. code: req.body.code,
  774. client_id: req.body.clientId,
  775. client_secret: config.TWITCH_SECRET,
  776. redirect_uri: req.body.redirectUri,
  777. grant_type: 'authorization_code'
  778. };
  779. // Step 1. Exchange authorization code for access token.
  780. request.post({ url: accessTokenUrl, form: formData, json: true }, function(err, response, accessToken) {
  781. var params = {
  782. oauth_token: accessToken.access_token
  783. };
  784. // Step 2. Retrieve information about the current user.
  785. request.get({ url: profileUrl, qs: params, json: true }, function(err, response, profile) {
  786. // Step 3a. Link user accounts.
  787. if (req.header('Authorization')) {
  788. User.findOne({ twitch: profile._id }, function(err, existingUser) {
  789. if (existingUser) {
  790. return res.status(409).send({ message: 'There is already a Twitch account that belongs to you' });
  791. }
  792. var token = req.header('Authorization').split(' ')[1];
  793. var payload = jwt.decode(token, config.TOKEN_SECRET);
  794. User.findById(payload.sub, function(err, user) {
  795. if (!user) {
  796. return res.status(400).send({ message: 'User not found' });
  797. }
  798. user.twitch = profile._id;
  799. user.picture = user.picture || profile.logo;
  800. user.displayName = user.name || profile.name;
  801. user.email = user.email || profile.email;
  802. user.save(function() {
  803. var token = createJWT(user);
  804. res.send({ token: token });
  805. });
  806. });
  807. });
  808. } else {
  809. // Step 3b. Create a new user account or return an existing one.
  810. User.findOne({ twitch: profile._id }, function(err, existingUser) {
  811. if (existingUser) {
  812. var token = createJWT(existingUser);
  813. return res.send({ token: token });
  814. }
  815. var user = new User();
  816. user.twitch = profile._id;
  817. user.picture = profile.logo;
  818. user.displayName = profile.name;
  819. user.email = profile.email;
  820. user.save(function() {
  821. var token = createJWT(user);
  822. res.send({ token: token });
  823. });
  824. });
  825. }
  826. });
  827. });
  828. });
  829. /*
  830. |--------------------------------------------------------------------------
  831. | Login with Bitbucket
  832. |--------------------------------------------------------------------------
  833. */
  834. app.post('/auth/bitbucket', function(req, res) {
  835. var accessTokenUrl = 'https://bitbucket.org/site/oauth2/access_token';
  836. var userApiUrl = 'https://bitbucket.org/api/2.0/user';
  837. var emailApiUrl = 'https://bitbucket.org/api/2.0/user/emails';
  838. var headers = {
  839. Authorization: 'Basic ' + new Buffer(req.body.clientId + ':' + config.BITBUCKET_SECRET).toString('base64')
  840. };
  841. var formData = {
  842. code: req.body.code,
  843. redirect_uri: req.body.redirectUri,
  844. grant_type: 'authorization_code'
  845. };
  846. // Step 1. Exchange authorization code for access token.
  847. request.post({ url: accessTokenUrl, form: formData, headers: headers, json: true }, function(err, response, body) {
  848. if (body.error) {
  849. return res.status(400).send({ message: body.error_description });
  850. }
  851. var params = {
  852. access_token: body.access_token
  853. };
  854. // Step 2. Retrieve information about the current user.
  855. request.get({ url: userApiUrl, qs: params, json: true }, function(err, response, profile) {
  856. // Step 2.5. Retrieve current user's email.
  857. request.get({ url: emailApiUrl, qs: params, json: true }, function(err, response, emails) {
  858. var email = emails.values[0].email;
  859. // Step 3a. Link user accounts.
  860. if (req.header('Authorization')) {
  861. User.findOne({ bitbucket: profile.uuid }, function(err, existingUser) {
  862. if (existingUser) {
  863. return res.status(409).send({ message: 'There is already a Bitbucket account that belongs to you' });
  864. }
  865. var token = req.header('Authorization').split(' ')[1];
  866. var payload = jwt.decode(token, config.TOKEN_SECRET);
  867. User.findById(payload.sub, function(err, user) {
  868. if (!user) {
  869. return res.status(400).send({ message: 'User not found' });
  870. }
  871. user.bitbucket = profile.uuid;
  872. user.email = user.email || email;
  873. user.picture = user.picture || profile.links.avatar.href;
  874. user.displayName = user.displayName || profile.display_name;
  875. user.save(function() {
  876. var token = createJWT(user);
  877. res.send({ token: token });
  878. });
  879. });
  880. });
  881. } else {
  882. // Step 3b. Create a new user account or return an existing one.
  883. User.findOne({ bitbucket: profile.id }, function(err, existingUser) {
  884. if (existingUser) {
  885. var token = createJWT(existingUser);
  886. return res.send({ token: token });
  887. }
  888. var user = new User();
  889. user.bitbucket = profile.uuid;
  890. user.email = email;
  891. user.picture = profile.links.avatar.href;
  892. user.displayName = profile.display_name;
  893. user.save(function() {
  894. var token = createJWT(user);
  895. res.send({ token: token });
  896. });
  897. });
  898. }
  899. });
  900. });
  901. });
  902. });
  903. /*
  904. |--------------------------------------------------------------------------
  905. | Unlink Provider
  906. |--------------------------------------------------------------------------
  907. */
  908. app.post('/auth/unlink', ensureAuthenticated, function(req, res) {
  909. var provider = req.body.provider;
  910. var providers = ['facebook', 'foursquare', 'google', 'github', 'instagram',
  911. 'linkedin', 'live', 'twitter', 'twitch', 'yahoo'];
  912. if (providers.indexOf(provider) === -1) {
  913. return res.status(400).send({ message: 'Unknown OAuth Provider' });
  914. }
  915. User.findById(req.user, function(err, user) {
  916. if (!user) {
  917. return res.status(400).send({ message: 'User Not Found' });
  918. }
  919. user[provider] = undefined;
  920. user.save(function() {
  921. res.status(200).end();
  922. });
  923. });
  924. });
  925. /*
  926. |--------------------------------------------------------------------------
  927. | Start the Server
  928. |--------------------------------------------------------------------------
  929. */
  930. app.listen(app.get('port'), app.get('host'), function() {
  931. console.log('Express server listening on port ' + app.get('port'));
  932. });