An error occurred while loading the file. Please try again.
account.js 20.44 KiB
const fs = require('fs')
const SamlStrategy = require('passport-saml').Strategy
const dbconn = require('../config/dbconn')
const methods = require('../functions/methods')
const gitlab = require('../functions/gitlab')
const constants = require('../config/const')
// pwd encryption
const bcrypt = require('bcryptjs');
const saltRounds = 10;
const salt = 64; // salt length
// forgot pwd
const async = require('async')
const crypto = require('crypto')
const mailer = require('../config/mailer')
const logoDir = 'public/upload/'
const defaultLogo = 'public/default/logo.png'
const tpGitlabURL = 'https://transfer.hft-stuttgart.de/gitlab/'
const tpGitlabPagesURL = 'https://transfer.hft-stuttgart.de/pages/'
const portalUser = require('../classes/user')
const projectInformation = require('../classes/website')
const projectRepo = require('../classes/repo')
module.exports = function (app, config, passport, lang) {
  // =========== PASSPORT =======
  passport.serializeUser(function (user, done) {
    done(null, user);
  });
  passport.deserializeUser(function (user, done) {
    done(null, user);
  });
  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
  function (profile, done) {
    return done(null, {
      id: profile.nameID,
      idFormat: profile.nameIDFormat,
      email: profile.email,
      firstName: profile.givenName,
      lastName: profile.sn
    });
  });
  passport.use(samlStrategy);
  // ============= SAML ==============
  app.post(config.passport.saml.path,
    passport.authenticate(config.passport.strategy,
failureRedirect: '/account/', failureFlash: true }), function (req, res) { res.redirect('/account/'); } ); // to generate Service Provider's XML metadata app.get('/saml/metadata', function(req, res) { res.type('application/xml'); var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync(__dirname + '/cert/cert.pem', 'utf8')); res.status(200).send(spMetadata); } ); // ======== APP ROUTES - ACCOUNT ==================== async function getLoggedInUserData(email) { let user = await methods.getUserByEmail(email) if (!user) { console.log('no user found') return null } else { 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) if (userGitlabId) { loggedInUser.setGitlabUserId(userGitlabId) } return loggedInUser } } app.get('/', async function (req, res) { if ( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) res.render(lang+'/account/home', { user: loggedInUser }); } }); app.get('/login', passport.authenticate(config.passport.strategy, { successRedirect: '/', failureRedirect: '/login' }) ) app.get('/logout', function (req, res) { if (req.user == null) { return res.redirect('/'); } req.user.nameID = req.user.id; req.user.nameIDFormat = req.user.idFormat; return samlStrategy.logout(req, function(err, uri) { req.logout(); if ( req.session ) { req.session.destroy((err) => { if(err) { return console.log(err);
} }); } return res.redirect(uri); }); }); app.get('/profile', async function (req, res) { if ( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if(loggedInUser.getVerificationStatus() != 1) { res.redirect('/account/') } else { res.render(lang+'/account/profile', { user: loggedInUser }) } } }) app.get('/services', async function(req, res){ if( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if(loggedInUser.getVerificationStatus() != 1) { // unverified users res.redirect('/account/') } else { let gitlabReposArr = [] let gitlabPagesArr = [] if(loggedInUser.getGitlabUserId()) { // for users who have activated their gitlab account let userProjects = await gitlab.getUserProjects(loggedInUser.getGitlabUserId()) if (!userProjects) { console.error("something went wrong") res.status(500).render(lang+'/500', { error: "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) } 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 }) } else { // for users who have not activated their gitlab account yet let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail()) if (!gitlabUser) { res.render(lang+'/account/services', { user: loggedInUser, gitlabRepos: null, gitlabPages: null }) } else {
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 }) } else { res.redirect('/account/services') } }) } } } } }) app.get('/security', async function (req, res) { if ( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if(loggedInUser.getVerificationStatus() == 1 && loggedInUser.getIdpStatus() == 1) { res.render(lang+'/account/security', { user: loggedInUser }) } else { res.redirect('/account/') } } }) app.post('/updateProfile', async function (req, res) { var userData = { salutation: req.body.inputSalutation, 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, } if ( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if (userData.email) { dbconn.user.query('UPDATE user SET ? WHERE email = "' +userData.email+'"', userData, function (err, rows, fields) { if (err) { res.flash('error', "Failed") } else { loggedInUser.updateProfile(userData.salutation, userData.title, userData.firstname, userData.lastname, userData.email, userData.organisation, userData.industry, userData.speciality) res.flash('success', 'Ihr Benutzerprofil wurde aktualisiert!') } res.redirect('/account/profile'); }) } } }); app.post('/changePwd', async function (req, res) { if( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email)
var currPwd = req.body.inputCurrPwd var newPwd = req.body.inputNewPwd var retypePwd = req.body.inputConfirm // 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 // 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 = constants.updatePasswordMailSubject mailer.options.html = constants.updatePasswordMailContent+'<div>'+constants.mailSignature+'</div>' mailer.transport.sendMail(mailer.options, function(err) { if (err) { console.log(err) } }); } res.redirect('/account/security') }) }); }); } } }) }) } }); app.get('/resendVerificationEmail', async function(req, res){ if (!req.isAuthenticated) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if (!loggedInUser) { res.redirect('/login') } else { let token = await methods.getVerificationTokenByUserId(loggedInUser.id) if (!token) { res.send(false) } else { // send email var emailSubject = "Bitte bestätigen Sie Ihr M4_LAB Benutzerkonto"
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/>' + constants.mailSignature + '</div>'; mailer.options.to = loggedInUser.email; mailer.options.subject = emailSubject; mailer.options.html = emailContent; mailer.transport.sendMail(mailer.options, function(err) { if (err) { console.log('cannot send email') throw err } }) res.send(true) } } } }) // ============= NEW GITLAB PAGES =========================== app.get('/newInformation', async function(req, res){ if ( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) let gitlabUser = await gitlab.getUserByEmail(loggedInUser.getEmail()) if (!gitlabUser) { // no user found res.redirect('/account/services') } else { res.render(lang+'/account/newInformation', { user: loggedInUser, gitlabUsername: gitlabUser.username }) } } }) app.post('/newInformation', async function(req, res) { if( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if (!req.body.name && !req.body.description) { res.flash('error', 'Bitte geben Sie die benötigten Daten ein') res.redirect('/account/newInformation') } else { let projectName = req.body.name.toLowerCase().replace(/\s/g, '-') let projectDesc = req.body.description let projectTemplate = req.body.template let newInformation = new projectInformation(loggedInUser.getGitlabUserId(), null, projectName, projectDesc, null, null) let newLogoFile = defaultLogo if (req.files) { newLogoFile = req.files.logo } async.waterfall([ function(callback){ // upload logo if (!req.files) { callback(null, newLogoFile) } else { newLogoFile.mv(logoDir + newLogoFile.name, function(err) { newLogoFile = logoDir+newLogoFile.name callback(err, newLogoFile) }) } }, 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.") } else { res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ") } res.redirect('/account/newInformation') } else { let newPagesData = newPages.data res.flash("success", "Ihre Webseite wurde erstellt, aber noch nicht veröffentlicht. Um Ihre Webseite endgültig zu veröffentlichen, "+ "schließen Sie die Einrichtung gemäß unten stehender Anleitung ab.") /* 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) } } ], function (err) { if(err) console.log(err) // remove logo if (req.files) { fs.unlink(newLogoFile, (err) => { if(err) console.log(err) }) } }) } } }) app.get('/updateInformation', async function(req, res){ if( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if(!req.query.id) { res.redirect('/account/services') } else { 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) { console.log(" ========= Project cannot be accessed, since it does not have an owner") res.redirect('/account/services') } else if (project.owner.id != loggedInUser.getGitlabUserId()) { console.log(" ========= Access denied: 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 }) } } } }) // update a website app.post('/updateInformation', async function(req, res){ if( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) if (!req.body.name && !req.body.description) { res.flash('error', 'Bitte geben Sie die benötigten Daten ein')
res.redirect('/account/updateInformation') } else { let projectName = req.body.name.toLowerCase().replace(/\s/g, '-') let projectDesc = req.body.description let updatedInformation = new projectInformation(loggedInUser.getGitlabUserId(), req.query.id, projectName, projectDesc, null, null) let newLogoFile async.waterfall([ 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) }) } }, async function(newLogoFile, callback){ // update gitlab page let updatedPages = await gitlab.updateProject(updatedInformation, newLogoFile) let pagesData = updatedPages.data if (updatedPages.error) { if(pagesData.message.name == "has already been taken") { res.flash("error", "Der Projektname ist bereits vergeben, bitte wählen Sie einen anderen Namen.") } else { res.flash("error", "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut. ") } } else { updatedInformation.setLogo(pagesData.avatar_url) updatedInformation.setPath(pagesData.path) res.flash("success", "Ihre Website wurde aktualisiert") } res.redirect('/account/updateInformation?id='+updatedInformation.getId()) } ], function (err) { if(err) console.log(err) if(newLogoFile){ // remove logo fs.unlink(newLogoFile, (err) => { if(err) console.log(err) }) } }) } } }) app.delete('/deleteProject', async function(req, res){ console.log("delete project") if( !req.isAuthenticated() ) { res.redirect('/login') } else { let loggedInUser = await getLoggedInUserData(req.user.email) let projectId = req.body.id if (projectId) { // check if the owner is valid let project = await gitlab.getProjectById(projectId) if (!project) { console.log(" ========= Error or no project found") } else if (!project.owner) { console.log(" ========= Project cannot be accessed, since it does not have an owner") } else if (project.owner.id != loggedInUser.getGitlabUserId()) { console.log(" ========= Access denied: Not your project") } else { // delete project let project = await gitlab.deleteProjectById(projectId) if (project.error) { res.flash("error", "Project cannot be deleted. Please try again.")
} } } res.redirect('/account/services') } }) }