root.js 10.3 KB
Newer Older
mntmn's avatar
mntmn committed
1
2
3
4
5
6
7
8
9
10
11
"use strict";

const config = require('config');

const redis = require('../helpers/redis');
const express = require('express');
const crypto = require('crypto');
const router = express.Router();
const mailer = require('../helpers/mailer');
const _ = require('underscore');

Wolfgang Knopki's avatar
Wolfgang Knopki committed
12
13
14
15
16
const fs = require('fs')
const SamlStrategy = require('passport-saml').Strategy
const passport = require('passport')
const Saml2js = require('saml2js');

mntmn's avatar
mntmn committed
17
18
19
20
21
const db = require('../models/db');
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const uuidv4 = require('uuid/v4');

Wolfgang Knopki's avatar
Wolfgang Knopki committed
22
23
24
25
26
27
28
29
30
31
32
33
34

// =========== 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.path,
35
      logoutUrl: config.logoutUrl,
Wolfgang Knopki's avatar
Wolfgang Knopki committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

      entryPoint: config.entryPoint,
      issuer: config.issuer,
      identifierFormat: null,

      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);

 // to generate Service Provider's XML metadata
  router.get('/saml/metadata',
    function(req, res) {
      res.type('application/xml');
      var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync('/cert/certificate.pem', 'utf8'));
      res.status(200).send(spMetadata);
    }
  );

65
router.post('/saml/SSO', passport.authenticate('saml', { failureRedirect: config.entryPoint+'/login', failureFlash: true}), function(req, res){
Wolfgang Knopki's avatar
Wolfgang Knopki committed
66
67
    const xmlResponse = req.body.SAMLResponse;
    const parser = new Saml2js(xmlResponse);
Wolfgang Knopki's avatar
Wolfgang Knopki committed
68
69
70
71
72
    const response = parser.toObject();
    const email = response["mail"];
    console.log(parser.toJSON());
    console.log("Nickname "+ response["givenName"])
    const nickname = response["givenName"];
73
    //check, if user exists, if not create.
Wolfgang Knopki's avatar
Wolfgang Knopki committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    db.User.findAll({where: {email: email}})
        .then(users => {
          if (users.length == 0) {
            crypto.randomBytes(16, function(ex, buf) {
                var token = buf.toString('hex');

                var u = {
                    _id: uuidv4(),
                    email: email,
                    account_type: "email",
                    nickname: nickname,
                    password_hash: "00000",
                    prefs_language: req.i18n.locale,
                    confirmation_token: token
                };

                db.User.create(u)
                    .error(err => {
                        res.sendStatus(400);
                    })
                    .then(u => {
                        var homeFolder = {
                            _id: uuidv4(),
                            name: req.i18n.__("home"),
                            space_type: "folder",
                            creator_id: u._id
                          };
                          db.Space.create(homeFolder)
                            .error(err => {
                              res.sendStatus(400);
                            })
                            .then(homeFolder => {
                              u.home_folder_id = homeFolder._id;
                              u.save()
                                .then(() => {
                                  // home folder created,
                                  // auto accept pending invites
                                  db.Membership.update({
                                    "state": "active"
                                  }, {
                                    where: {
                                      "email_invited": u.email,
                                      "state": "pending"
                                    }
                                  });
                                  res.status(201).json({});
                                })
                                .error(err => {
                                  res.status(400).json(err);
                                });
                            })
                    });
            });
          }
        }).then(user =>{
         db.User.findOne({where: {email: email}})
Wolfgang Knopki's avatar
Wolfgang Knopki committed
130
                .error(err => {
Wolfgang Knopki's avatar
Wolfgang Knopki committed
131
                  res.sendStatus(404);
Wolfgang Knopki's avatar
Wolfgang Knopki committed
132
                })
Wolfgang Knopki's avatar
Wolfgang Knopki committed
133
134
135
136
137
138
139
140
141
142
                .then(user => {
                    crypto.randomBytes(48, function(ex, buf) {
                                  var token = buf.toString('hex');

                                  var session = {
                                    user_id: user._id,
                                    token: token,
                                    ip: req.ip,
                                    device: "web",
                                    created_at: new Date(),
143
                                    url : config.entryPoint
Wolfgang Knopki's avatar
Wolfgang Knopki committed
144
145
146
147
148
149
150
151
                                  };

                                  db.Session.create(session)
                                    .error(err => {
                                      console.error("Error creating Session:",err);
                                      res.redirect(500, "/");
                                    })
                                    .then(() => {
152
                                      var domain = (process.env.NODE_ENV == "production") ? new URL(config.get("endpoint")).hostname : req.headers.hostname;
Wolfgang Knopki's avatar
Wolfgang Knopki committed
153
154
                                      console.log("session set successfully");
                                      res.cookie('sdsession', token, { domain: domain, httpOnly: true });
155
                                      res.redirect(302, config.entryPoint)
Wolfgang Knopki's avatar
Wolfgang Knopki committed
156
157
                                    });
                        });
Wolfgang Knopki's avatar
Wolfgang Knopki committed
158
                });
Wolfgang Knopki's avatar
Wolfgang Knopki committed
159
         });
Wolfgang Knopki's avatar
Wolfgang Knopki committed
160
161
});

mntmn's avatar
mntmn committed
162
router.get('/', (req, res) => {
163
  res.render('index', { config:config, user:req.user });
mntmn's avatar
mntmn committed
164
165
166
167
168
169
170
});

router.get('/ping', (req, res) => {
  res.status(200).json({"status": "ok"})
});

router.get('/spaces', (req, res) => {
171
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
172
173
174
});

router.get('/not_found', (req, res) => {
175
  res.render('not_found', {});
mntmn's avatar
mntmn committed
176
177
178
});

router.get('/confirm/:token', (req, res) => {
179
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
180
181
182
});

router.get('/folders/:id', (req, res) => {
183
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
184
185
186
});

router.get('/signup', (req, res) => {
187
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
188
189
190
});

router.get('/accept/:id', (req, res) => {
191
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
192
193
194
});

router.get('/password-reset', (req, res) => {
195
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
196
197
198
});

router.get('/password-confirm/:token', (req, res) => {
199
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
});

router.get('/de/*', (req, res) => {
  res.redirect("/t/de");
});

router.get('/de', (req, res) => {
  res.redirect("/t/de");
});

router.get('/fr/*', (req, res) => {
  res.redirect("/t/fr");
});

router.get('/fr', (req, res) => {
  res.redirect("/t/fr");
});
217

Mejans's avatar
Mejans committed
218
219
220
router.get('/oc/*', (req, res) => {
  res.redirect("/t/oc");
});
mntmn's avatar
mntmn committed
221

Mejans's avatar
Mejans committed
222
223
224
router.get('/oc', (req, res) => {
  res.redirect("/t/oc");
});
225

mntmn's avatar
mntmn committed
226
227
228
229
230
231
232
233
234
235
236
237
router.get('/en/*', (req, res) => {
  res.redirect("/t/en");
});

router.get('/en', (req, res) => {
  res.redirect("/t/end");
});

router.get('/account', (req, res) => {
  res.render('spacedeck');
});

Wolfgang Knopki's avatar
Wolfgang Knopki committed
238
239
240
241
242
243
244
245
246
247
router.get('/login', passport.authenticate('saml',
                           {
                             successRedirect: '/',
                             failureRedirect: '/login'
                           })
);


//  res.render('spacedeck', { config:config, user:req.user });
//});
mntmn's avatar
mntmn committed
248

249
250
251
252
253
254
255
256
257
258
259
function samlLogout(req,res){
console.log("enter samlLogout")
try{
    samlStrategy.logout(req, function(err,uri){
        if(err) console.log("can't generate logout URL: ${err}");
        req.logout();
        var token = req.cookies['sdsession'];
        db.Session.findOne({where: {token: token}})
            .then(session => {
                session.destroy();
            });
260
        var domain = (process.env.NODE_ENV == "production") ? new URL(config.get("endpoint")).hostname : req.headers.hostname;
261
262
263
264
265
266
267
268
269
270
271
272
        res.clearCookie('sdsession', { domain: domain });
        console.log("clear Cookie")
        res.redirect(uri);
    });
}catch(err){
    if(err) console.log(`Exception on URL: ${err}`);
    req.logout();
    var token = req.cookies['sdsession'];
    db.Session.findOne({where: {token: token}})
        .then(session => {
            session.destroy();
        });
273
    var domain = (process.env.NODE_ENV == "production") ? new URL(config.get("endpoint")).hostname : req.headers.hostname;
274
275
276
277
278
279
    res.clearCookie('sdsession', { domain: domain });
    console.log("clear Cookie on error")
    res.redirect("/login");
    }
}

mntmn's avatar
mntmn committed
280
router.get('/logout', (req, res) => {
281
282
283
284
285
286
    console.log("logout pressed")
    if (req.user == null) {
        console.log("req.user == null");
        return res.redirect('/');
    }
    samlLogout(req,res);
mntmn's avatar
mntmn committed
287
288
});

289
290
291
292
293
294
295
296
297
298
299
300
router.get('/saml/SLO', (req, res, next) => {
        console.log("received logout request");
        var token=req.cookies['sdsession'];
        if(token) {
            return next();
        } else {
            return res.redirect('/'); //best be landing page of everything
        }
    },
    samlLogout
);

mntmn's avatar
mntmn committed
301
302
303
304
305
306
307
308
309
router.get('/t/:id', (req, res) => {
  res.cookie('spacedeck_locale', req.params.id, { maxAge: 900000, httpOnly: true });
  var path = "/";
  if (req.query.r=="login" || req.query.r=="signup") {
    path = "/"+req.query.r;
  }
  res.redirect(path);
});

310
311
312
313
router.get('/s/:hash', (req, res) => {
  var hash = req.params.hash;
  if (hash.split("-").length > 0) {
    hash = hash.split("-")[0];
mntmn's avatar
mntmn committed
314
  }
mntmn's avatar
mntmn committed
315

316
  db.Space.findOne({where: {"edit_hash": hash}}).then(function (space) {
mntmn's avatar
mntmn committed
317
318
    if (space) {
      if (req.accepts('text/html')){
319
	      res.redirect("/spaces/"+space._id + "?spaceAuth=" + hash);
mntmn's avatar
mntmn committed
320
      } else {
mntmn's avatar
mntmn committed
321
	      res.status(200).json(space);
mntmn's avatar
mntmn committed
322
      }
mntmn's avatar
mntmn committed
323
    } else {
mntmn's avatar
mntmn committed
324
      if (req.accepts('text/html')) {
325
	      res.status(404).render('not_found', {});
mntmn's avatar
mntmn committed
326
      } else {
mntmn's avatar
mntmn committed
327
	      res.status(404).json({});
mntmn's avatar
mntmn committed
328
      }
mntmn's avatar
mntmn committed
329
330
331
332
333
    }
  });
});

router.get('/spaces/:id', (req, res) => {
334
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
335
336
});

Wolfgang Knopki's avatar
Wolfgang Knopki committed
337
module.exports = {router: router, passport:passport};