Archived
2

added passreset and mail helper

This commit is contained in:
VLE2FE 2020-04-23 17:46:00 +02:00
parent 1a3fdc567d
commit 4e68267bfd
8 changed files with 220 additions and 8 deletions

View File

@ -141,14 +141,17 @@ Email:
email:
type: string
example: john.doe@bosch.com
User:
allOf:
- $ref: 'oas.yaml#/components/schemas/_Id'
- $ref: 'oas.yaml#/components/schemas/Email'
UserName:
properties:
name:
type: string
example: johndoe
User:
allOf:
- $ref: 'oas.yaml#/components/schemas/_Id'
- $ref: 'oas.yaml#/components/schemas/UserName'
- $ref: 'oas.yaml#/components/schemas/Email'
properties:
pass:
type: string
writeOnly: true

View File

@ -171,11 +171,13 @@
content:
application/json:
schema:
$ref: 'oas.yaml#/components/schemas/Email'
allOf:
- $ref: 'oas.yaml#/components/schemas/UserName'
- $ref: 'oas.yaml#/components/schemas/Email'
responses:
200:
$ref: 'oas.yaml#/components/responses/Ok'
401:
$ref: 'oas.yaml#/components/responses/401'
404:
$ref: 'oas.yaml#/components/responses/404'
500:
$ref: 'oas.yaml#/components/responses/500'

26
package-lock.json generated
View File

@ -203,6 +203,14 @@
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"requires": {
"follow-redirects": "1.5.10"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -848,6 +856,24 @@
"is-buffer": "~2.0.3"
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",

View File

@ -17,6 +17,7 @@
"@hapi/joi": "^17.1.1",
"@types/mocha": "^5.2.7",
"@types/node": "^13.1.6",
"axios": "^0.19.2",
"basic-auth": "^2.0.1",
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",

View File

@ -51,6 +51,7 @@ export default class db {
});
});
mongoose.connection.once('open', () => {
mongoose.set('useFindAndModify', false);
console.log(process.env.NODE_ENV === 'test' ? '' : `Connected to ${connectionString}`);
this.state.db = mongoose.connection;
done();

64
src/helpers/mail.ts Normal file
View File

@ -0,0 +1,64 @@
import axios from 'axios';
// sends an email
export default (mailAddress, subject, content, f) => { // callback, executed empty or with error
if (process.env.NODE_ENV === 'production') {
const mailService = JSON.parse(process.env.VCAP_SERVICES).Mail[0];
axios({
method: 'post',
url: mailService.credentials.uri + '/email',
auth: {username: mailService.credentials.username, password: mailService.credentials.password},
data: {
recipients: [{to: mailAddress}],
subject: {content: subject},
body: {
content: content,
contentType: "text/html"
},
from: {
eMail: "dfop@bosch-iot.com",
password: "PlasticsOfFingerprintDigital"
}
}
})
.then(() => {
f();
})
.catch((err) => {
f(err);
});
}
else if (process.env.NODE_ENV === 'test') {
console.log('Sending mail to ' + mailAddress + ': -- ' + subject + ' -- ' + content);
f();
}
else { // dev
axios({
method: 'get',
url: 'https://digital-fingerprint-of-plastics-mail-test.apps.de1.bosch-iot-cloud.com/api',
data: {
method: 'post',
url: '/email',
data: {
recipients: [{to: mailAddress}],
subject: {content: subject},
body: {
content: content,
contentType: "text/html"
},
from: {
eMail: "dfop-test@bosch-iot.com",
password: "PlasticsOfFingerprintDigital"
}
}
}
})
.then(() => {
f();
})
.catch((err) => {
f(err);
});
}
}

View File

@ -105,4 +105,96 @@ describe('/user/new', () => {
done();
});
});
});
describe('/user/passreset', () => {
let server;
before(done => {
process.env.port = '2999';
process.env.NODE_ENV = 'test';
db.connect('test', done);
});
beforeEach(done => {
delete require.cache[require.resolve('../index')]; // prevent loading from cache
server = require('../index');
db.drop(err => { // reset database
if (err) return done(err);
db.loadJson(require('../test/db.json'), done);
});
});
afterEach(done => {
server.close(done);
});
it('returns the ok response', done => {
supertest(server)
.post('/user/passreset')
.send({
email: 'jane.doe@bosch.com',
name: 'janedoe'
})
.expect('Content-type', /json/)
.expect(200)
.end((err, res) => {
if (err) done(err);
should(res.body).be.eql({status: 'OK'});
done();
});
});
it('returns 404 for wrong username/email combo', done => {
supertest(server)
.post('/user/passreset')
.send({
email: 'jane.doe@bosch.com',
name: 'admin'
})
.expect('Content-type', /json/)
.expect(404)
.end((err, res) => {
if (err) done(err);
should(res.body).be.eql({status: 'Not found'});
done();
});
});
it('returns 404 for unknown username', done => {
supertest(server)
.post('/user/passreset')
.send({
email: 'jane.doe@bosch.com',
name: 'admin'
})
.expect('Content-type', /json/)
.expect(404)
.end((err, res) => {
if (err) done(err);
should(res.body).be.eql({status: 'Not found'});
done();
});
});
it('changes the user password', done => {
UserModel.find({name: 'janedoe'}).lean().exec( 'find', (err, data) => {
if (err) return done(err);
const oldpass = data[0].pass;
supertest(server)
.post('/user/passreset')
.send({
email: 'jane.doe@bosch.com',
name: 'janedoe'
})
.expect('Content-type', /json/)
.expect(200)
.end((err, res) => {
if (err) done(err);
should(res.body).be.eql({status: 'OK'});
UserModel.find({name: 'janedoe'}).lean().exec( 'find', (err, data) => {
if (err) return done(err);
should(data[0].pass).not.eql(oldpass);
done();
});
});
});
});
});

View File

@ -3,6 +3,7 @@ import mongoose from 'mongoose';
import bcrypt from 'bcryptjs';
import UserValidate from './validate/user';
import UserModel from '../models/user';
import mail from '../helpers/mail';
const router = express.Router();
@ -11,7 +12,6 @@ router.get('/users', (req, res) => {
});
router.post('/user/new', (req, res, next) => {
console.log(req.authDetails);
if (!req.auth(res, ['admin'], 'basic')) return;
// validate input
@ -40,4 +40,27 @@ router.post('/user/new', (req, res, next) => {
});
});
router.post('/user/passreset', (req, res, next) => {
// check if user/email combo exists
UserModel.find({name: req.body.name, email: req.body.email}).lean().exec( 'find', (err, data) => {
if (err) next(err);
if (data.length === 1) { // it exists
const newPass = Math.random().toString(36).substring(2);
bcrypt.hash(newPass, 10, (err, hash) => { // password hashing
if (err) next(err);
UserModel.findOneAndUpdate({name: req.body.name, email: req.body.email}, {pass: hash}, err => {
if (err) next(err);
mail(data[0].email, 'Your new password for the DFOP database', 'Hi, <br><br> You requested to reset your password.<br>Your new password is:<br><br>' + newPass + '<br><br>If you did not request a password reset, talk to the sysadmin quickly!<br><br>Have a nice day.<br><br>The DFOP team', err => {
if (err) next(err);
res.json({status: 'OK'});
});
});
});
}
else {
res.status(404).json({status: 'Not found'});
}
});
});
module.exports = router;