routes-account.js 33 KB
Newer Older
1
2
3
4
const fs = require('fs')
const SamlStrategy = require('passport-saml').Strategy
const dbconn = require('./dbconn')
const methods = require('./methods')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
5
const gitlab = require('./gitlab')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
6
// pwd encryption
7
8
9
const bcrypt = require('bcryptjs');
const saltRounds = 10;
const salt = 64; // salt length
Rosanny Sihombing's avatar
Rosanny Sihombing committed
10
// forgot pwd
11
12
const async = require('async')
const crypto = require('crypto')
13
const mailer = require('./mailer')
14
15
const logoDir = 'public/upload/'
const tpGitlabURL = 'https://transfer.hft-stuttgart.de/gitlab/'
Rosanny Sihombing's avatar
Rosanny Sihombing committed
16
const tpGitlabPagesURL = 'https://transfer.hft-stuttgart.de/pages/'
Rosanny Sihombing's avatar
Rosanny Sihombing committed
17

18
19
20
const portalUser = require('../classes/user')
const projectInformation = require('../classes/website')
const projectRepo = require('../classes/repo')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
21

22
module.exports = function (app, config, passport, i18n) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
23
24
25
26
27
28
29
30
31
32

  // =========== PASSPORT =======
  passport.serializeUser(function (user, done) {
    done(null, user);
  });

  passport.deserializeUser(function (user, done) {
    done(null, user);
  });

Varun Srivastava's avatar
Varun Srivastava committed
33
34
35
36
  const mailSignature = 'Mit den besten Grüßen,<br/>das Transferportal-Team der HFT Stuttgart<br/><br/>' +
    'Transferportal der Hochschule für Technik Stuttgart<br/>' +
    'Schellingstr. 24   70174 Stuttgart<br/>' +
    'm4lab@hft-stuttgart.de<br/>' +
Rosanny Sihombing's avatar
Rosanny Sihombing committed
37
    '<a href="https://transfer.hft-stuttgart.de">https://transfer.hft-stuttgart.de</a><br/>' +
38
39
40
41
42
    '<a href="http://www.hft-stuttgart.de/Aktuell/"><img border="0" alt="HFT" src="https://m4lab.hft-stuttgart.de/img/signature/hft_logo.png" width="30" height="30"></a>  &nbsp;' +
    '<a href="http://www.facebook.com/hftstuttgart"><img border="0" alt="Facebook" src="https://m4lab.hft-stuttgart.de/img/signature/fb_bw.png" width="30" height="30"></a>  &nbsp;' +
    '<a href="https://www.instagram.com/hft_stuttgart/"><img border="0" alt="Instagram" src="https://m4lab.hft-stuttgart.de/img/signature/instagram_bw.png" width="30" height="30"></a>  &nbsp;' +
    '<a href="https://twitter.com/hft_presse"><img border="0" alt="Twitter" src="https://m4lab.hft-stuttgart.de/img/signature/twitter_bw.png" width="30" height="30"></a>  &nbsp;' +
    '<a href="https://www.youtube.com/channel/UCi0_JfF2qMZbOhOnNH5PyHA"><img border="0" alt="Youtube" src="https://m4lab.hft-stuttgart.de/img/signature/youtube_bw.png" width="30" height="30"></a>  &nbsp;' +
Varun Srivastava's avatar
Varun Srivastava committed
43
    '<a href="http://www.hft-stuttgart.de/Aktuell/Presse-Marketing/SocialMedia/Snapcode HFT_Stuttgart.jpg/photo_view">' +
44
45
    '<img border="0" alt="Snapchat" src="https://m4lab.hft-stuttgart.de/img/signature/snapchat_bw.png" width="30" height="30"></a>' +
    '<br/><img border="0" src="https://m4lab.hft-stuttgart.de/img/signature/inno_bw.png" width="150" height="100">'
Varun Srivastava's avatar
Varun Srivastava committed
46

Rosanny Sihombing's avatar
Rosanny Sihombing committed
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  var samlStrategy = new SamlStrategy({
      // URL that goes from the Identity Provider -> Service Provider
      callbackUrl: config.passport.saml.path,
      // Base address to call logout requests
      logoutUrl: config.passport.saml.logoutUrl,
      
      entryPoint: config.passport.saml.entryPoint,
      issuer: config.passport.saml.issuer,
      identifierFormat: null,
      
      // Service Provider private key
      decryptionPvk: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
      // Service Provider Certificate
      privateCert: fs.readFileSync(__dirname + '/cert/key.pem', 'utf8'),
      // Identity Provider's public key
      cert: fs.readFileSync(__dirname + '/cert/cert_idp.pem', 'utf8'),
      
      validateInResponseTo: false,
      disableRequestedAuthnContext: true
66
67
68
69
70
71
72
73
  },
  function (profile, done) {
    return done(null, {
      id: profile.nameID,
      idFormat: profile.nameIDFormat,
      email: profile.email,
      firstName: profile.givenName,
      lastName: profile.sn
Rosanny Sihombing's avatar
Rosanny Sihombing committed
74
    });
75
  });
Rosanny Sihombing's avatar
Rosanny Sihombing committed
76
77
  
  passport.use(samlStrategy);
78
79
80
81
82

  // ============= SAML ==============
  app.post(config.passport.saml.path,
    passport.authenticate(config.passport.strategy,
      {
83
        failureRedirect: '/account/',
84
85
86
        failureFlash: true
      }),
    function (req, res) {
87
      res.redirect('/account/');
88
89
90
91
    }
  );

  // to generate Service Provider's XML metadata
92
  app.get('/saml/metadata',
93
94
95
96
97
98
    function(req, res) {
      res.type('application/xml');
      var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync(__dirname + '/cert/cert.pem', 'utf8'));
      res.status(200).send(spMetadata);
    }
  );
Wolfgang Knopki's avatar
Wolfgang Knopki committed
99
100
101
102
103
104
105

  // ================ test i18n ==================
  i18n.setLocale('de');
  app.get('/de', function(req, res) {
    var greeting = i18n.__('Hello World')
    res.send(greeting)
  });
106

Wolfgang Knopki's avatar
Wolfgang Knopki committed
107
  var lang = 'DE'
Rosanny Sihombing's avatar
DE    
Rosanny Sihombing committed
108

Wolfgang Knopki's avatar
Wolfgang Knopki committed
109
  // ======== APP ROUTES - ACCOUNT ====================
Rosanny Sihombing's avatar
DE    
Rosanny Sihombing committed
110
  var updatePasswordMailSubject = "Ihr Passwort für das Transferportal wurde gespeichert."
Varun Srivastava's avatar
Varun Srivastava committed
111
  var updatePasswordMailContent = '<div>Lieber Nutzer,<br/><br/>Ihr Passwort wurde erfolgreich geändert.<br/><br/>' + mailSignature + '</div>';
Rosanny Sihombing's avatar
DE    
Rosanny Sihombing committed
112

113
114
115
116
117
118
119
120
121
122
123
124
125
  async function getLoggedInUserData(email) {
    let user = await methods.getUserByEmail(email)
    let loggedInUser = new portalUser(
      user.id, email, user.salutation, user.title, user.firstname, user.lastname, user.industry, user.organisation, user.speciality, user.m4lab_idp, null, user.verificationStatus
    )
    
    let userGitlabId = await methods.getGitlabId(loggedInUser.id)
    loggedInUser.setGitlabUserId(userGitlabId)

    return loggedInUser
  }

  app.get('/', async function (req, res) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
126
127
128
    if ( !req.isAuthenticated() ) {
      res.redirect('/login')
    } else {
129
130
131
132
133
      let loggedInUser = await getLoggedInUserData(req.user.email)
      
      res.render(lang+'/account/home', {
        user: loggedInUser
      });
134
    }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
135
136
  });

Rosanny Sihombing's avatar
Rosanny Sihombing committed
137
  app.get('/login',
Rosanny Sihombing's avatar
Rosanny Sihombing committed
138
139
140
141
142
    passport.authenticate(config.passport.strategy, {
      successRedirect: '/',
      failureRedirect: '/login'
    })
  )
Rosanny Sihombing's avatar
Rosanny Sihombing committed
143

144
145
  app.get('/logout', function (req, res) {
    if (req.user == null) {
146
      return res.redirect('/');
Rosanny Sihombing's avatar
Rosanny Sihombing committed
147
    }
Wolfgang Knopki's avatar
Wolfgang Knopki committed
148

149
150
151
152
    req.user.nameID = req.user.id;
    req.user.nameIDFormat = req.user.idFormat;
    return samlStrategy.logout(req, function(err, uri) {
      req.logout();
153

154
155
156
157
158
159
160
      if ( req.session ) {
        req.session.destroy((err) => {
          if(err) {
              return console.log(err);
          }
        });
      }
161

162
163
164
      return res.redirect(uri);
    });
  });
Rosanny Sihombing's avatar
Rosanny Sihombing committed
165

166
167
  app.get('/profile', async function (req, res) {
    if ( !req.isAuthenticated() ) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
168
      res.redirect('/login')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
169
    } else {
170
      let loggedInUser = await getLoggedInUserData(req.user.email)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
171
172
173
174
175
176
177
      if(loggedInUser.getVerificationStatus() != 1) {
        res.redirect('/account/')
      } else {
        res.render(lang+'/account/profile', {
          user: loggedInUser
        })
      }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
178
    }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
179
  })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
180

Rosanny Sihombing's avatar
Rosanny Sihombing committed
181
  app.get('/services', async function(req, res){
182
    if( !req.isAuthenticated() ) {
183
184
      res.redirect('/login')
    } else {
185
      let loggedInUser = await getLoggedInUserData(req.user.email)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
186
187
      if(loggedInUser.getVerificationStatus() != 1) { // unverified users
        res.redirect('/account/')
188
      } else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
189
190
        let gitlabReposArr = []
        let gitlabPagesArr = []
Rosanny Sihombing's avatar
Rosanny Sihombing committed
191

Rosanny Sihombing's avatar
Rosanny Sihombing committed
192
        if(loggedInUser.getGitlabUserId()) { // for users who have activated their gitlab account
Rosanny Sihombing's avatar
Rosanny Sihombing committed
193
194
195
196
197
198
199
200
201
202
          let userProjects = await gitlab.getUserProjects(loggedInUser.getGitlabUserId())
          if (!userProjects)
            res.status(500).send("something went wrong :/")
          
          for (project in userProjects) {
            if (userProjects[project].tag_list.includes('website')) {
              let page = {
                projectInformation: new projectInformation(loggedInUser.getGitlabUserId(), userProjects[project].id, userProjects[project].name,
                  userProjects[project].description, userProjects[project].avatar_url, userProjects[project].path_with_namespace),
                pipelineStatus: await gitlab.getProjectPipelineLatestStatus(userProjects[project].id)
203
              }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
204
205
206
207
208
209
210
211
212
213
214
215
              gitlabPagesArr.push(page)
            } else {
              let repo = new projectRepo(loggedInUser.getGitlabUserId(), userProjects[project].id, userProjects[project].name,
                userProjects[project].description, userProjects[project].avatar_url, userProjects[project].path_with_namespace)
              gitlabReposArr.push(repo)
            }
          }

          res.render(lang+'/account/services', {
            user: loggedInUser,
            gitlabRepos: gitlabReposArr,
            gitlabPages: gitlabPagesArr
Rosanny Sihombing's avatar
Rosanny Sihombing committed
216
          })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
217
        } else { // for users who have not activated their gitlab account yet
Rosanny Sihombing's avatar
Rosanny Sihombing committed
218
219
220
221
222
223
224
225
226
          let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail())
          // RS: if error, then what?
          let gitlabActivationData = {
            user_id: loggedInUser.getId(),
            gitlab_userId: gitlabUser.id}
          // RS: update to await
          methods.addGitlabUser(gitlabActivationData, function(err){
            if(err) {
              res.status(500).render(lang+'/500', { error: err })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
227
            } else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
228
229
              loggedInUser.setGitlabUserId(gitlabActivationData.gitlab_userId)
              res.redirect('/account/services')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
230
231
            }
          })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
232
        }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
233
      }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
234
    }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
235
  })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
236

237
238
  app.get('/security', async function (req, res) {
    if ( !req.isAuthenticated() ) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
239
      res.redirect('/login')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
240
    } else {
241
      let loggedInUser = await getLoggedInUserData(req.user.email)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
242
243
244
245
246
247
248
      if(loggedInUser.getVerificationStatus() == 1 && loggedInUser.getIdpStatus() == 1) {
        res.render(lang+'/account/security', {
          user: loggedInUser
        })
      } else {
        res.redirect('/account/')
      }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
249
    }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
250
  })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
251

252
  app.post('/updateProfile', async function (req, res) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
253
    var userData = {
Rosanny Sihombing's avatar
DE    
Rosanny Sihombing committed
254
      salutation: req.body.inputSalutation,
Rosanny Sihombing's avatar
Rosanny Sihombing committed
255
256
257
258
259
260
261
262
      title: req.body.inputTitle,
      firstname: req.body.inputFirstname,
      lastname: req.body.inputLastname,
      email: req.body.inputEmail,
      organisation: req.body.inputOrganisation,
      industry: req.body.inputIndustry,
      speciality: req.body.inputSpeciality,
    }
263

264
    if ( !req.isAuthenticated() ) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
265
266
      res.redirect('/login')
    } else {
267
      let loggedInUser = await getLoggedInUserData(req.user.email)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
268
      if (userData.email) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
269
        dbconn.user.query('UPDATE user SET ? WHERE email = "' +userData.email+'"', userData, function (err, rows, fields) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
270
            if (err) {
271
              res.flash('error', "Failed")
Rosanny Sihombing's avatar
Rosanny Sihombing committed
272
273
            }
            else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
274
275
              loggedInUser.updateProfile(userData.salutation, userData.title, userData.firstname, userData.lastname, userData.email,
                userData.organisation, userData.industry, userData.speciality)
276
              res.flash('success', 'Ihr Benutzerprofil wurde aktualisiert!')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
277
            }
Wolfgang Knopki's avatar
Wolfgang Knopki committed
278
            res.redirect('/account/profile');
Rosanny Sihombing's avatar
Rosanny Sihombing committed
279
280
281
282
        })
      }
    }
  });
283

284
285
  app.post('/changePwd', async function (req, res) {
    if( !req.isAuthenticated() ) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
286
287
      res.redirect('/login')
    } else {
288
289
      let loggedInUser = await getLoggedInUserData(req.user.email)

Rosanny Sihombing's avatar
Rosanny Sihombing committed
290
291
292
293
      var currPwd = req.body.inputCurrPwd
      var newPwd = req.body.inputNewPwd
      var retypePwd = req.body.inputConfirm

Rosanny Sihombing's avatar
Rosanny Sihombing committed
294
295
296
297
298
299
300
      // update - get userId from loggedInUser
      dbconn.user.query('SELECT password FROM credential WHERE user_id='+loggedInUser.getId(), function (err, rows, fields) {
        if (err) {
          console.error(err)
          res.status(500).render(lang+'/500', { error: err })
        }
        var userPwd = rows[0].password
301

Rosanny Sihombing's avatar
Rosanny Sihombing committed
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
        // check if the password is correct
        bcrypt.compare(currPwd, userPwd, function(err, isMatch) {
          if (err) {
            console.error(err)
            res.status(500).render(lang+'/500', { error: err })
          } else if (!isMatch) {
            res.flash('error', "Das Passwort ist leider falsch. Bitte überprüfen Sie Ihre Eingabe.")
            res.redirect('/account/security')
          } else {
            if ( newPwd != retypePwd ) {
              res.flash('error', 'Passwörter stimmen nicht überein. Bitte stellen Sie sicher, dass Sie das Passwort beide Male genau gleich eingeben.')
              res.redirect('/account/security')
            } else {
              // update password
              bcrypt.genSalt(saltRounds, function(err, salt) {
                bcrypt.hash(newPwd, salt, function(err, hash) {
                  var credentialData = {
                    password: hash,
                    user_id: userId
                  }
                  methods.updateCredential(credentialData, function(err){
                    if (err) {
                      res.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
                      throw err
                    } else {
                      res.flash('success', "Passwort aktualisiert!")
                      mailer.options.to = req.user.email
                      mailer.options.subject = updatePasswordMailSubject
                      mailer.options.html = updatePasswordMailContent
                      mailer.transport.sendMail(mailer.options, function(err) {
                        if (err) { console.log(err) }
                      });
                    }
                    res.redirect('/account/security')
                  })
                });
              });
            }
          }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
341
        })
342
      })
343
    }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
344
345
346
  });

  app.get('/forgotPwd', function (req, res) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
347
    res.render(lang+'/account/forgotPwd', {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
348
349
350
351
352
      user: req.user
    });
  });

  app.post('/forgotPwd', function(req, res, next) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
353
    let emailAddress = req.body.inputEmail
Rosanny Sihombing's avatar
Rosanny Sihombing committed
354
355
356
357
358
359
360
361
362
363
364
    async.waterfall([
      function(done) {
        crypto.randomBytes(20, function(err, buf) {
          var token = buf.toString('hex');
          done(err, token);
        });
      },
      function(token, done) {
        methods.checkUserEmail(emailAddress, function(err, user){
          if (user) {
            console.log("email: user found");
Rosanny Sihombing's avatar
DE    
Rosanny Sihombing committed
365
            var emailSubject = "Ihre Passwort-Anfrage an das Transferportal der HFT Stuttgart";
Varun Srivastava's avatar
Varun Srivastava committed
366
367
            // var emailContent = "Lieber Nutzer,\n\n"+
            //   "wir haben Ihre Anfrage zur Erneuerung Ihres Passwortes erhalten. Falls Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-Mail.\n\n"+
Rosanny Sihombing's avatar
Rosanny Sihombing committed
368
            //   "Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: http://localhost:9989/reset/" + token + "\n" + // localhost
Varun Srivastava's avatar
Varun Srivastava committed
369
370
371
372
373
374
375
            //   "Dieser Link ist aus Sicherheitsgründen nur für 1 Stunde gültig.\n\n"+mailSignature

            var emailContent = '<div>Lieber Nutzer, Varun<br/><br/>' +
              '<p>wir haben Ihre Anfrage zur Erneuerung Ihres Passwortes erhalten. Falls Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-Mail.<br/><br/>' +
              'Sie können Ihr Passwort mit dem Klick auf diesen Link ändern: http://m4lab.hft-stuttgart.de/account/reset/' + token + '<br/>' + // test server
              'Dieser Link ist aus Sicherheitsgründen nur für 1 Stunde gültig.<br/></p>' + mailSignature + '</div>';
            
376
377
378
379
380
381
            var credentialData = {
              user_id: user.id,
              resetPasswordToken: token,
              resetPasswordExpires: Date.now() + 3600000 // 1 hour
            }
            methods.updateCredential(credentialData, function(err) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
382
383
              done(err, token, user);
            });
384
385

            // send email
386
387
            mailer.options.to = emailAddress;
            mailer.options.subject = emailSubject;
Varun Srivastava's avatar
Varun Srivastava committed
388
            mailer.options.html = emailContent;
389
            mailer.transport.sendMail(mailer.options, function(err) {
390
391
              done(err, 'done');
            });
Rosanny Sihombing's avatar
Rosanny Sihombing committed
392
393
          }
          else {
394
            done(err, 'no user found');
Rosanny Sihombing's avatar
Rosanny Sihombing committed
395
396
397
398
399
          }
        });
      }
    ], function(err) {
      if (err) {
400
        res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
Rosanny Sihombing's avatar
Rosanny Sihombing committed
401
402
      }
      else {
403
        res.flash('success', 'Wenn Ihre E-Mail-Adresse registriert ist, wurde eine E-Mail mit dem weiteren Vorgehen an ' + emailAddress + ' versendet.');
Rosanny Sihombing's avatar
Rosanny Sihombing committed
404
      }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
405
      res.redirect('/account/forgotPwd');
Rosanny Sihombing's avatar
Rosanny Sihombing committed
406
407
408
409
    });
  });

  app.get('/reset/:token', function(req, res) {
410
    methods.getUserByToken(req.params.token, function(err, user){
Rosanny Sihombing's avatar
Rosanny Sihombing committed
411
      if (!user) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
412
413
        res.flash('error', 'Der Schlüssel zum zurücksetzen des Passworts ist ungültig oder abgelaufen.')
        res.redirect('/account/forgotPwd')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
414
415
      }
      else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
416
        res.render(lang+'/account/reset')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
417
418
419
420
421
      }
    });
  });

  app.post('/reset/:token', function(req, res) {
422
    var newPwd = req.body.inputNewPwd
423
    methods.getUserByToken(req.params.token, function(err, user){
Rosanny Sihombing's avatar
Rosanny Sihombing committed
424
      if (user) {
425
        // encrypt password
Rosanny Sihombing's avatar
Rosanny Sihombing committed
426
        bcrypt.genSalt(saltRounds, function(err, salt) {
Wolfgang Knopki's avatar
Wolfgang Knopki committed
427
          bcrypt.hash(newPwd, salt, function(err, hash) {
428
429
430
431
432
433
            var credentialData = {
              password: hash,
              user_id: user.user_id
            }
            // update password
            methods.updateCredential(credentialData, function(err){
Rosanny Sihombing's avatar
Rosanny Sihombing committed
434
              if (err) {
435
                res.flash('error', "Datenbankfehler: Passwort kann nicht geändert werden.")
Rosanny Sihombing's avatar
Rosanny Sihombing committed
436
437
438
                throw err
              }
              else {
439
                res.flash('success', "Passwort aktualisiert!")
440
                // send notifiaction email
441
442
                mailer.options.to = user.email
                mailer.options.subject = updatePasswordMailSubject
Varun Srivastava's avatar
Varun Srivastava committed
443
                mailer.options.html = updatePasswordMailContent
444
                mailer.transport.sendMail(mailer.options, function(err) {
445
446
447
448
449
                  if (err) {
                    console.log(err)
                  }
                });
                // redirect to login page
450
                res.redirect('/login')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
451
452
453
454
455
456
              }
            })
          });
        });
      }
      else {
457
        res.flash('error', "User not found.")
458
        res.redirect('/login')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
459
460
      }
    });
461

Rosanny Sihombing's avatar
Rosanny Sihombing committed
462
463
  });

Rosanny Sihombing's avatar
Rosanny Sihombing committed
464
  // ============= NEW GITLAB PAGES ===========================
465
  
Rosanny Sihombing's avatar
Rosanny Sihombing committed
466
  app.get('/newInformation', async function(req, res){
467
    if ( !req.isAuthenticated() ) {
468
469
      res.redirect('/login')
    } else {
470
      let loggedInUser = await getLoggedInUserData(req.user.email)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
471
472
473
474
475
476
477
478
479
      let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail())
      if (!gitlabUser) { // no user found
        res.redirect('/account/service')
      } else {
        res.render(lang+'/account/newInformation', {
          user: loggedInUser,
          gitlabUsername: gitlabUser.username
        })
      }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
480
    }
481
  })
482
483
  app.post('/newInformation', async function(req, res) {
    if( !req.isAuthenticated() ) {
484
485
      res.redirect('/login')
    } else {
486
487
      let loggedInUser = await getLoggedInUserData(req.user.email)

488
      if (!req.body.name && !req.body.description) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
489
        res.flash('error', 'Bitte geben Sie die benötigten Daten ein')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
490
        res.redirect('/account/newInformation')
491
492
493
      } else {
        let projectName = req.body.name.toLowerCase().replace(/\s/g, '-')
        let projectDesc = req.body.description
Rosanny Sihombing's avatar
Rosanny Sihombing committed
494
495
        let projectTemplate = req.body.template
        let newInformation = new projectInformation(loggedInUser.getGitlabUserId(), null, projectName, projectDesc, null, null)
496
497
            
        if (!req.files) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
498
          res.flash('error', 'Bitte geben Sie ein Projektlogo an.')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
499
          res.redirect('/account/newInformation')
500
501
502
503
504
505
506
507
508
        } else {
          let newLogoFile = req.files.logo
          async.waterfall([
            function(callback){ // upload logo
              newLogoFile.mv(logoDir + newLogoFile.name, function(err) {
                newLogoFile = logoDir+newLogoFile.name
                callback(err, newLogoFile)
              })
            },
Rosanny Sihombing's avatar
Rosanny Sihombing committed
509
510
511
512
513
            async function(newLogoFile){ // create a new GitLab Page
              let newPages = await gitlab.createNewPages(newInformation, newLogoFile, projectTemplate)
              if (newPages.error) {
                if(newPages.data.message.name == "has already been taken") {
                  res.flash("error", "Der Projektname '"+newInformation.getName()+"' ist bereits vergeben, bitte wählen Sie einen anderen Namen.")
514
                } else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
515
                  res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ")
516
                }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
517
518
519
520
521
522
523
524
525
                res.redirect('/account/newInformation')
              } else {
                let newPagesData = newPages.data
        
                //res.flash("success", "Ihre Webseite wurde erstellt, aber noch nicht veröffentlicht. Bitte fahren Sie mit Schritten 2 und 3 fort, um Ihre Webseite zu veröffentlichen.")
                res.flash("success", "Your website will be published AFTER you complete your website by following the provided guideline below."+
                  "\r\n Your website URL: "+tpGitlabPagesURL+newPagesData.path_with_namespace+"/home/")
                res.redirect('/account/updateInformation?id='+newPagesData.id)
              }
526
527
528
529
530
531
532
533
534
535
            }
          ], function (err) {
            if(err) console.log(err)
            // remove logo
            fs.unlink(newLogoFile, (err) => {
              if(err) console.log(err)
            })
          })
        }
      }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
536
537
538
    }
  })

Rosanny Sihombing's avatar
Rosanny Sihombing committed
539
  app.get('/updateInformation', async function(req, res){
540
    if( !req.isAuthenticated() ) {
541
542
      res.redirect('/login')
    } else {
543
544
      let loggedInUser = await getLoggedInUserData(req.user.email)

545
546
547
      if(!req.query.id) {
        res.redirect('/account/services')
      } else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
        let project = await gitlab.getProjectById(req.query.id)
        if (!project) {
          console.log(" =================== error or no project found")
          res.redirect('/account/services')
        } else if (project.owner.id != loggedInUser.getGitlabUserId()) {
          console.log(" =================== not your project")
          res.redirect('/account/services')
        } else {
          let curInformation = new projectInformation(loggedInUser.getGitlabUserId(), req.query.id, project.name, project.description,
            project.avatar_url, project.path_with_namespace)
          
          res.render(lang+'/account/updateInformation', {
            user: loggedInUser,
            information: curInformation
          })
        }
564
565
566
      }
    }
  })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
567

568
569
  app.post('/updateInformation', async function(req, res){
    if( !req.isAuthenticated() ) {
570
571
      res.redirect('/login')
    } else {
572
573
      let loggedInUser = await getLoggedInUserData(req.user.email)

574
      if (!req.body.name && !req.body.description) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
575
        res.flash('error', 'Bitte geben Sie die benötigten Daten ein')
Rosanny Sihombing's avatar
Rosanny Sihombing committed
576
        res.redirect('/account/updateInformation')
577
      } else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
578
579
        let projectName = req.body.name.toLowerCase().replace(/\s/g, '-')
        let projectDesc = req.body.description
Rosanny Sihombing's avatar
Rosanny Sihombing committed
580
        let updatedInformation = new projectInformation(loggedInUser.getGitlabUserId(), req.query.id, projectName, projectDesc, null, null)
581
        let newLogoFile
Rosanny Sihombing's avatar
Rosanny Sihombing committed
582

Rosanny Sihombing's avatar
Rosanny Sihombing committed
583
        async.waterfall([
584
585
586
587
588
589
590
591
592
593
          function(callback){ // upload logo
            if(!req.files) {
              callback(null, newLogoFile)
            } else {
              newLogoFile = req.files.logo
              newLogoFile.mv(logoDir + newLogoFile.name, function(err) {
                newLogoFile = logoDir + newLogoFile.name
                callback(err, newLogoFile)
              })
            }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
594
          },
Rosanny Sihombing's avatar
Rosanny Sihombing committed
595
596
597
598
599
600
          async function(newLogoFile, callback){ // update gitlab page
            let updatedPages = await gitlab.updateProject(updatedInformation, newLogoFile)
            let pagesData = updatedPages.data
            if (pagesData.error) {
              if(pagesData.message.name == "has already been taken") {
                res.flash("error", "Der Projektname ist bereits vergeben, bitte wählen Sie einen anderen Namen.")
601
              } else {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
602
                res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ")
Rosanny Sihombing's avatar
Rosanny Sihombing committed
603
              }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
604
605
606
            } else {
              updatedInformation.setLogo(pagesData.avatar_url)
              updatedInformation.setPath(pagesData.path)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
607
              res.flash("success", "Ihre Website wurde aktualisiert")
Rosanny Sihombing's avatar
Rosanny Sihombing committed
608
609
            }
            res.redirect('/account/updateInformation?id='+updatedInformation.getId())
610
611
612
613
614
615
          }
        ], function (err) {
          if(err) console.log(err)
          if(newLogoFile){ // remove logo
            fs.unlink(newLogoFile, (err) => {
              if(err) console.log(err)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
616
617
            })
          }
618
        })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
619
620
      }
    }
621
622
623
624
  })

  // RS: delete projektInformation?

625
  // ============= NEW USERS REGISTRATION ===========================
626
  app.get('/registration', function(req, res) {
Rosanny Sihombing's avatar
Rosanny Sihombing committed
627
    res.render(lang+'/account/registration')
628
629
630
631
632
  })
  app.post('/registration', function(req, res) {
    // user data
    var curDate = new Date()
    var userData = {
Rosanny Sihombing's avatar
DE    
Rosanny Sihombing committed
633
      salutation: req.body.inputSalutation,
634
635
636
637
638
639
640
641
      title: req.body.inputTitle,
      firstname: req.body.inputFirstname,
      lastname: req.body.inputLastname,
      email: req.body.inputEmail,
      organisation: req.body.inputOrganisation,
      industry: req.body.inputIndustry,
      speciality: req.body.inputSpeciality,
      createdDate: curDate.toISOString().slice(0,10)
Rosanny Sihombing's avatar
Rosanny Sihombing committed
642
    }
643

644
645
646
647
648
649
    var userEmail = userData.email
    var pos = userEmail.indexOf('@')
    var emailLength = userEmail.length
    var emailDomain = userEmail.slice(pos, emailLength);

    if ( emailDomain.toLowerCase() == "@hft-stuttgart.de") {
650
651
        res.flash('error', "Fehlgeschlagen: HFT-Account")
        res.redirect('/account/registration')
652
653
654
655
656
657
658
659
    }
    else {
      let token
      async.waterfall([
        function(done) {
          crypto.randomBytes(20, function(err, buf) {
            token = buf.toString('hex');
            done(err, token);
660
          });
661
662
663
664
665
666
667
668
669
        },
        // encrypt password
        function(token, done) {
          bcrypt.genSalt(saltRounds, function(err, salt) {
            bcrypt.hash(req.body.inputPassword, salt, function(err, hash) {
              var newAccount = {
                profile: userData,
                password: hash,
                verificationToken: token
670
              }
671
672
673
674
675
676
677
678
              done(err, newAccount)
            });
          });
        },
        // save data
        function(newAccount, err) {
          methods.registerNewUser(newAccount, function(err){
            if (err) {
679
              res.flash('error', "Fehlgeschlagen")
680
681
682
683
            }
            else {
              // send email
              var emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto"
Varun Srivastava's avatar
Varun Srivastava committed
684
685
686
687
688
689
690
691
692
693
694
              // var emailContent = "Lieber Nutzer,\n\n"+
              //     "vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart.\n"+
              //     "Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: "+config.app.host+"/verifyAccount?token="+token+"\n"+
              //     "Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.\n\n"+
              //     "Sollten Sie sich selbst nicht mit Ihren Daten am Transferportal registriert haben, ignorieren Sie diese E-Mail bitte.\n\n"+mailSignature
              var emailContent = '<div>Lieber Nutzer,<br/><br/>' +
                '<p>vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart. <br/>' +
                'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: ' + config.app.host + '/verifyAccount?token=' + token +
                '<br/><br/>' +
                'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.</p><br/>' + mailSignature +
                '</div>';
695
696
              mailer.options.to = req.body.inputEmail;
              mailer.options.subject = emailSubject;
Varun Srivastava's avatar
Varun Srivastava committed
697
              mailer.options.html = emailContent;
698
699
700
701
702
703
704
              mailer.transport.sendMail(mailer.options, function(err) {
                if (err) {
                  console.log('cannot send email')
                  throw err
                }
              })
              // user feedback
705
              res.flash('success', 'Vielen Dank für Ihre Registrierung!'+'\r\n\r\n'+
706
707
708
709
710
711
712
713
                'Wir haben Ihnen eine E-Mail an Ihre verwendete Adresse gesendet. Diese enthält einen Link zur Bestätigung Ihres Accounts.'+'\r\n'+
                'Wenn Sie die Mail nicht in ihrem Postfach vorfinden, prüfen Sie bitte auch Ihren Spam-Ordner.')
            }
            res.redirect('/account/registration')
          })
        }
      ])
    }
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  })

  // ============= USER VERIFICATION ================================
  app.get("/verifyAccount", function(req, res){
    methods.getUserIdByVerificationToken(req.query.token, function(userId, err){
      if (userId) {
        let userData = {
          id: userId,
          verificationStatus: 1
        }
        methods.verifyUserAccount(userData, function(err){
          if (err) {
            console.log("Error: "+err)
            res.render(lang+'/account/verification', {
              status: false
            });
          }
          else {
732
733
734
735
736
737
738
739
            // send welcome email after successful account verification
            methods.getUserById(userId, function(data, err){
              if (err) {
                console.log("Error: "+err)
              }
              else {
                // send email
                var emailSubject = "Herzlich willkommen"
Varun Srivastava's avatar
Varun Srivastava committed
740
741
742
                var emailContent = '<div>Lieber Nutzer,<br/><br/>' +
                  '<p>herzlich willkommen beim Transferportal der HFT Stuttgart!<br/>' +
                  'Sie können nun alle Dienste des Portals nutzen.<p/><br/>' + mailSignature;
743
744
                mailer.options.to = data.email;
                mailer.options.subject = emailSubject;
Varun Srivastava's avatar
Varun Srivastava committed
745
                mailer.options.html = emailContent;
746
747
748
749
750
751
752
753
754
                mailer.transport.sendMail(mailer.options, function(err) {
                  if (err) {
                    console.log('cannot send email')
                    throw err
                  }
                })
              }
            })

755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
            res.render(lang+'/account/verification', {
              status: true
            });
          }
        })
      }
      else {
        res.render(lang+'/account/verification', {
          status: null
        });
      }
    })
  })
  app.get("/resendVerificationEmail", function(req, res){
    if (req.isAuthenticated()) {
      var emailAddress = req.user.email
      
      methods.getUserIdByEmail(req.user.email, function(userId, err) {
        if (!err) {
          // get token
          methods.getVerificationTokenByUserId(userId, function(token, err){
            if (!err) {
              if (token) {
                // send email
                var emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto"
Varun Srivastava's avatar
Varun Srivastava committed
780
781
782
783
784
785
786
787
788
789
                // var emailContent = "Lieber Nutzer,\n\n"+
                //     "vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart. "+ 
                //     "\nUm Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: "+config.app.host+"/verifyAccount?token="+token+
                //     "\n\nOhne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.\n\n"+mailSignature
                var emailContent = '<div>Lieber Nutzer,<br/><br/>' +
                  '<p>vielen Dank für Ihre Anmeldung am Transferportal der HFT Stuttgart. <br/>' +
                  'Um Ihre Anmeldung zu bestätigen, klicken Sie bitte diesen Link: ' + config.app.host + '/verifyAccount?token=' + token +
                  '<br/><br/>' +
                  'Ohne Bestätigung Ihres Kontos müssen wir Ihr Konto leider nach 7 Tagen löschen.</p><br/>' + mailSignature +
                  '</div>';
790
791
                mailer.options.to = emailAddress;
                mailer.options.subject = emailSubject;
Varun Srivastava's avatar
Varun Srivastava committed
792
                mailer.options.html = emailContent;
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
                mailer.transport.sendMail(mailer.options, function(err) {
                  if (err) {
                    console.log('cannot send email')
                    throw err
                  }
                })
                res.send(true)
              }
              else {
                res.send(false)
              }
            }
            else {
              console.log(err)
            }
          })
        }
      })
    }
812
  })
Rosanny Sihombing's avatar
Rosanny Sihombing committed
813

814
815
816
817
818
819
820
821
822
823
824
825
  app.get('/email/:email', function(req, res) {
    methods.checkUserEmail(req.params.email, function(err, user){
      if (!err) {
        if (user) {
          res.send(false)
        }
        else {
          res.send(true)
        }  
      }
    })
  })
Wolfgang Knopki's avatar
Wolfgang Knopki committed
826
827

  app.get('/contact', function (req, res) {
828
829
830
831
    res.render(lang+'/account/contact', {
      user: req.user
    })
  })
Wolfgang Knopki's avatar
Wolfgang Knopki committed
832

Rosanny Sihombing's avatar
Rosanny Sihombing committed
833
  app.post('/contact', function(req, res, next) {
Wolfgang Knopki's avatar
Wolfgang Knopki committed
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
      //methods.currentDate();
      let emailAddress = req.body.inputEmail;
      let supportAddress = "support-transfer@hft-stuttgart.de";
      let inputName = req.body.name;
      let inputContent = req.body.message;
      let emailContent = "Es wurde eine Anfrage an das Transferportal gestellt: \n\n NAME: " + inputName + "\n NACHRICHT:\n "+ inputContent;
      let emailSubject = "Ihre Anfrage an das Transferportal";
      async.waterfall([
        function(done) {
            // send email
            mailer.options.to = supportAddress;
            mailer.options.cc = emailAddress;
            mailer.options.subject = emailSubject;
            mailer.options.text = emailContent;
            mailer.transport.sendMail(mailer.options, function(err) {
                done(err, 'done');
              });
          }
      ], function(err) {
        if (err) {
854
          res.flash('error', 'Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.');
Wolfgang Knopki's avatar
Wolfgang Knopki committed
855
856
        }
        else {
857
          res.flash('success', 'Vielen Dank für Ihre Anfrage. Wir melden uns baldmöglichst bei Ihnen. Eine Kopie Ihrer Anfrage wurde an ' + emailAddress + ' versandt.');
Wolfgang Knopki's avatar
Wolfgang Knopki committed
858
        }
Rosanny Sihombing's avatar
Rosanny Sihombing committed
859
        res.redirect('/account/contact')
860
861
862
863
      })
  })

}