users.js 9.36 KB
Newer Older
mntmn's avatar
mntmn committed
1
2
3
"use strict";

var config = require('config');
4
5
const db = require('../../models/db');
const uuidv4 = require('uuid/v4');
mntmn's avatar
mntmn committed
6
const os = require('os');
mntmn's avatar
mntmn committed
7
8
9

var mailer = require('../../helpers/mailer');
var uploader = require('../../helpers/uploader');
mntmn's avatar
mntmn committed
10
var importer = require('../../helpers/importer');
mntmn's avatar
mntmn committed
11

Martin Guether's avatar
Martin Guether committed
12
var bcrypt = require('bcryptjs');
13
var crypto = require('crypto');
mntmn's avatar
mntmn committed
14
15
16
17
18
19
20
var swig = require('swig');
var async = require('async');
var _ = require('underscore');
var fs = require('fs');
var request = require('request');
var gm = require('gm');
var validator = require('validator');
21
var URL = require('url').URL;
mntmn's avatar
mntmn committed
22
23
24

var express = require('express');
var router = express.Router();
25
var glob = require('glob');
mntmn's avatar
mntmn committed
26
27
28

router.get('/current', function(req, res, next) {
  if (req.user) {
29
30
31
32
33
34
35
36
37
    var u = _.clone(req.user.dataValues);
    delete u.password_hash;
    delete u.password_reset_token;
    delete u.confirmation_token;
    u.token = req.cookies['sdsession'];

    console.log(u);
    
    res.status(200).json(u);
mntmn's avatar
mntmn committed
38
39
40
41
42
  } else {
    res.status(401).json({"error":"user_not_found"});
  }
});

43
// create user
mntmn's avatar
mntmn committed
44
router.post('/', function(req, res) {
45
  if (!req.body["email"] || !req.body["password"]) {
mntmn's avatar
mntmn committed
46
    res.status(400).json({"error":"email or password missing"});
47
    return;
mntmn's avatar
mntmn committed
48
  }
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
  
  var email = req.body["email"].toLowerCase();
  var nickname = req.body["nickname"];
  var password = req.body["password"];
  var password_confirmation = req.body["password_confirmation"];

  if (password_confirmation != password) {
    res.status(400).json({"error":"password_confirmation"});
    return;
  }
  
  if (!validator.isEmail(email)) {
    res.status(400).json({"error":"email_invalid"});
    return;
  }
  
  var createUser = function() {
    bcrypt.genSalt(10, function(err, salt) {
      bcrypt.hash(password, salt, function(err, hash) {
        crypto.randomBytes(16, function(ex, buf) {
          var token = buf.toString('hex');

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

          db.User.create(u)
            .error(err => {
              res.sendStatus(400);
            })
            .then(u => {
              var homeSpace = {
                _id: uuidv4(),
                name: req.i18n.__("home"),
                space_type: "folder",
                creator_id: u._id
              };
              db.Space.create(homeSpace)
                .error(err => {
                  res.sendStatus(400);
                })
                .then(homeSpace => {
                  u.home_folder_id = homeSpace._id;
                  u.save()
                    .then(() => {
                      res.status(201).json({});
                      
                      mailer.sendMail(u.email, req.i18n.__("confirm_subject"), req.i18n.__("confirm_body"), {
                        action: {
                          link: config.endpoint + "/confirm/" + u.confirmation_token,
                          name: req.i18n.__("confirm_action")
mntmn's avatar
mntmn committed
106
107
                        }
                      });
108
109
110
111
112
113
114
                    })
                    .error(err => {
                      res.status(400).json(err);
                    });
                })
            });
        });
mntmn's avatar
mntmn committed
115
      });
116
117
118
119
120
121
122
123
124
125
126
127
    });
  };
  
  db.User.findAll({where: {email: email}})
    .then(users => {
      if (users.length == 0) {
        //var domain = email.slice(email.lastIndexOf('@')+1);
        createUser();
      } else {
        res.status(400).json({"error":"user_email_already_used"});
      }
    })
mntmn's avatar
mntmn committed
128
129
});

130
router.get('/current', function(req, res, next) {
mntmn's avatar
mntmn committed
131
132
133
134
135
136
137
138
  if (req.user) {
    res.status(200).json(req.user);
  } else {
    res.status(401).json({"error":"user_not_found"});
  }
});

router.put('/:id', function(req, res, next) {
139
  // TODO explicit whitelisting
mntmn's avatar
mntmn committed
140
141
142
143
144
145
  var user = req.user;
  if (user._id == req.params.id) {
    var newAttr = req.body;
    newAttr.updated_at = new Date();
    delete newAttr['_id'];

146
147
    db.User.update(newAttr, {where: {"_id": user._id}}).then(function(updatedUser) {
      res.status(200).json(newAttr);
mntmn's avatar
mntmn committed
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
    });
  } else {
    res.sendStatus(403);
  }
});

router.post('/:id/password', function(req, res, next) {
  var user = req.user;
  var old_password = req.body.old_password;
  var pass = req.body.new_password;

  if (pass.length >= 6) {
    if (user._id == req.params.id) {
      if (bcrypt.compareSync(old_password, user.password_hash)) {
        bcrypt.genSalt(10, function(err, salt) {
          bcrypt.hash(pass, salt, function(err, hash) {
            user.password_hash = hash;
165
166
            user.save().then(function() {
              res.sendStatus(204);
mntmn's avatar
mntmn committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
            });
          });
        });
      } else {
        res.status(403).json({"error": "old password wrong"});
      }
    } else {
      res.status(403).json({"error": "wrong user"});
    }
  } else {
    res.status(400).json({"error": "password_to_short"});
  }
});

router.delete('/:id',  (req, res, next) => {
  const user = req.user;
  if(user._id == req.params.id) {
    if (user.account_type == 'email') {
      if (bcrypt.compareSync(req.query.password, user.password_hash)) {
        user.remove((err) => {
          if(err)res.status(400).json(err);
          else res.sendStatus(204);
        });
      } else {
        res.bad_request("password_incorrect");
      }
    } else {
      user.remove((err) => {
195
        if (err) res.status(400).json(err);
mntmn's avatar
mntmn committed
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
        else res.sendStatus(204);
      });
    }
  }
  else res.status(403).json({error: ""});
});

router.put('/:user_id/confirm', (req, res) => {
  const token = req.body.token;
  const user = req.user;

  if (user.confirmation_token === token) {
    user.confirmation_token = null;
    user.confirmed_at = new Date();
    user.save(function(err, updatedUser) {
      if(err) {
        res.sendStatus(400);
      } else {
        res.status(200).json(updatedUser);
      }
    });
  } else {
    res.sendStatus(400);
  }
});

router.post('/:user_id/avatar', (req, res, next) => {
  const user = req.user;
  const filename = "u"+req.user._id+"_"+(new Date().getTime())+".jpeg"

mntmn's avatar
mntmn committed
226
227
  const localFilePath = os.tmpdir()+"/"+filename;
  const localResizedFilePath = os.tmpdir()+"/resized_"+filename;
mntmn's avatar
mntmn committed
228
229
230
231
232
233
234
235
236
237
238
  const writeStream = fs.createWriteStream(localFilePath);
  const stream = req.pipe(writeStream);

  req.on('end', function() {
    gm(localFilePath).resize(200, 200).autoOrient().write(localResizedFilePath, (err) => {
      if (err) res.status(400).json(err);
      else {
        uploader.uploadFile(filename, "image/jpeg", localResizedFilePath, (err, url) => {
          if (err) res.status(400).json(err);
          else {
            user.avatar_thumb_uri = url;
239
240
241
242
243
244
245
246
247
            user.save().then(() => {
              fs.unlink(localResizedFilePath, (err) => {
                if (err) {
                  console.error(err);
                  res.status(400).json(err);
                } else {
                  res.status(200).json(user);
                }
              });
mntmn's avatar
mntmn committed
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
            });
          }
        });
      }
    });
  });
});

router.post('/feedback', function(req, res, next) {
  var text = req.body.text;
  // FIXME
  mailer.sendMail("support@example.org", "Support Request by " + req.user.email, text, {reply_to: req.user.email});
  res.sendStatus(201);
});

router.post('/password_reset_requests', (req, res, next) => {
  const email = req.query.email;
265
266
267
268
269
270
271
272
273
274
275
276
  db.User.findOne({where: {"email": email}}).then((user) => {
    if (user) {
      crypto.randomBytes(16, (ex, buf) => {
        user.password_reset_token = buf.toString('hex');
        user.save().then(updatedUser => {
          mailer.sendMail(email, req.i18n.__("password_reset_subject"), req.i18n.__("password_reset_body"), {action: {
            link: config.endpoint + "/password-confirm/" + user.password_reset_token,
            name: req.i18n.__("password_reset_action")
          }});
          res.status(201).json({});
        });
      });
mntmn's avatar
mntmn committed
277
    } else {
278
      res.status(404).json({"error": "error_unknown_email"});
mntmn's avatar
mntmn committed
279
280
281
282
283
284
285
    }
  });
});

router.post('/password_reset_requests/:confirm_token/confirm', function(req, res, next) {
  var password = req.body.password;

Hirunatan's avatar
Hirunatan committed
286
  db.User
287
288
289
290
291
    .findOne({where: {"password_reset_token": req.params.confirm_token}})
    .then((user) => {
      if (user) {
        bcrypt.genSalt(10, (err, salt) => {
          bcrypt.hash(password, salt, function(err, hash) {
mntmn's avatar
mntmn committed
292

293
294
295
296
297
298
299
300
            user.password_hash = hash;
            user.password_token = null;
            user.save(function(err, updatedUser){
              if (err) {
                res.sendStatus(400);
              } else {
                res.sendStatus(201);
              }
mntmn's avatar
mntmn committed
301
302
            });
          });
303
304
305
        });
      } else {
        res.sendStatus(404);
mntmn's avatar
mntmn committed
306
307
308
309
310
311
312
313
314
315
316
317
      }
    });
});

router.post('/:user_id/confirm', function(req, res, next) {
  mailer.sendMail(req.user.email, req.i18n.__("confirm_subject"), req.i18n.__("confirm_body"), { action:{
    link: config.endpoint + "/confirm/" + req.user.confirmation_token,
    name: req.i18n.__("confirm_action")
  }});
  res.sendStatus(201);
});

318
319
320
321
322
323
router.get('/:user_id/importables', function(req, res, next) {
  glob('*.zip', function(err, files) {
    res.status(200).json(files);
  });
});

mntmn's avatar
mntmn committed
324
325
326
327
328
329
330
331
332
router.get('/:user_id/import', function(req, res, next) {
  if (req.query.zip) {
    res.send("importing");
    importer.importZIP(req.user, req.query.zip);
  } else {
    res.sendStatus(400);
  }
});

mntmn's avatar
mntmn committed
333
module.exports = router;