root.js 10.5 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

      entryPoint: config.entryPoint,
      issuer: config.issuer,
      identifierFormat: null,
Wolfgang Knopki's avatar
Wolfgang Knopki committed
40
41
42
      //skipRequestCompression: true,
      //authnRequestBinding: "HTTP-POST",
      //disableRequestACSUrl: true,
Wolfgang Knopki's avatar
Wolfgang Knopki committed
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

      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');
Wolfgang Knopki's avatar
Wolfgang Knopki committed
63
64
65
      //var spMetadata = samlStrategy.generateServiceProviderMetadata(fs.readFileSync('/cert/certificate.pem', 'utf8'));
      var spMetadata = samlStrategy.generateServiceProviderMetadata();
           res.status(200).send(spMetadata);
Wolfgang Knopki's avatar
Wolfgang Knopki committed
66
67
68
    }
  );

Wolfgang Knopki's avatar
Wolfgang Knopki committed
69
router.post('/saml/SSO', passport.authenticate('saml', { failureRedirect: config.endpoint + "/login", failureFlash: true}), function(req, res){
Wolfgang Knopki's avatar
Wolfgang Knopki committed
70
71
    const xmlResponse = req.body.SAMLResponse;
    const parser = new Saml2js(xmlResponse);
Wolfgang Knopki's avatar
Wolfgang Knopki committed
72
73
74
75
76
    const response = parser.toObject();
    const email = response["mail"];
    console.log(parser.toJSON());
    console.log("Nickname "+ response["givenName"])
    const nickname = response["givenName"];
77
    //check, if user exists, if not create.
Wolfgang Knopki's avatar
Wolfgang Knopki committed
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
130
131
132
133
    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
134
                .error(err => {
Wolfgang Knopki's avatar
Wolfgang Knopki committed
135
                  res.sendStatus(404);
Wolfgang Knopki's avatar
Wolfgang Knopki committed
136
                })
Wolfgang Knopki's avatar
Wolfgang Knopki committed
137
138
139
140
141
142
143
144
145
146
                .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(),
Wolfgang Knopki's avatar
Wolfgang Knopki committed
147
                                    url : config.endpoint + "/"
Wolfgang Knopki's avatar
Wolfgang Knopki committed
148
149
150
151
152
153
154
155
                                  };

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

mntmn's avatar
mntmn committed
166
router.get('/', (req, res) => {
167
  res.render('index', { config:config, user:req.user });
mntmn's avatar
mntmn committed
168
169
170
171
172
173
174
});

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

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

router.get('/not_found', (req, res) => {
179
  res.render('not_found', {});
mntmn's avatar
mntmn committed
180
181
182
});

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

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

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

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

router.get('/password-reset', (req, res) => {
199
  res.render('spacedeck', { config:config, user:req.user });
mntmn's avatar
mntmn committed
200
201
202
});

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

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");
});
221

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

Mejans's avatar
Mejans committed
226
227
228
router.get('/oc', (req, res) => {
  res.redirect("/t/oc");
});
229

mntmn's avatar
mntmn committed
230
231
232
233
234
235
236
237
238
239
240
241
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
242
243
244
245
246
247
248
249
250
251
router.get('/login', passport.authenticate('saml',
                           {
                             successRedirect: '/',
                             failureRedirect: '/login'
                           })
);


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

253
254
255
256
257
258
259
260
261
262
263
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();
            });
264
        var domain = (process.env.NODE_ENV == "production") ? new URL(config.get("endpoint")).hostname : req.headers.hostname;
265
266
267
268
269
270
271
272
273
274
275
276
        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();
        });
277
    var domain = (process.env.NODE_ENV == "production") ? new URL(config.get("endpoint")).hostname : req.headers.hostname;
278
279
280
281
282
283
    res.clearCookie('sdsession', { domain: domain });
    console.log("clear Cookie on error")
    res.redirect("/login");
    }
}

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

293
294
295
296
297
298
299
300
301
302
303
304
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
305
306
router.get('/t/:id', (req, res) => {
  res.cookie('spacedeck_locale', req.params.id, { maxAge: 900000, httpOnly: true });
Wolfgang Knopki's avatar
Wolfgang Knopki committed
307
  var path = config.endpoint + "/";
mntmn's avatar
mntmn committed
308
  if (req.query.r=="login" || req.query.r=="signup") {
Wolfgang Knopki's avatar
Wolfgang Knopki committed
309
    path = config.endpoint + "/"+req.query.r;
mntmn's avatar
mntmn committed
310
311
312
313
  }
  res.redirect(path);
});

314
315
316
317
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
318
  }
mntmn's avatar
mntmn committed
319

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

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

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