added passreset and mail helper
This commit is contained in:
parent
1a3fdc567d
commit
4e68267bfd
@ -141,14 +141,17 @@ Email:
|
|||||||
email:
|
email:
|
||||||
type: string
|
type: string
|
||||||
example: john.doe@bosch.com
|
example: john.doe@bosch.com
|
||||||
User:
|
UserName:
|
||||||
allOf:
|
|
||||||
- $ref: 'oas.yaml#/components/schemas/_Id'
|
|
||||||
- $ref: 'oas.yaml#/components/schemas/Email'
|
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
example: johndoe
|
example: johndoe
|
||||||
|
User:
|
||||||
|
allOf:
|
||||||
|
- $ref: 'oas.yaml#/components/schemas/_Id'
|
||||||
|
- $ref: 'oas.yaml#/components/schemas/UserName'
|
||||||
|
- $ref: 'oas.yaml#/components/schemas/Email'
|
||||||
|
properties:
|
||||||
pass:
|
pass:
|
||||||
type: string
|
type: string
|
||||||
writeOnly: true
|
writeOnly: true
|
||||||
|
@ -171,11 +171,13 @@
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: 'oas.yaml#/components/schemas/Email'
|
allOf:
|
||||||
|
- $ref: 'oas.yaml#/components/schemas/UserName'
|
||||||
|
- $ref: 'oas.yaml#/components/schemas/Email'
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
401:
|
404:
|
||||||
$ref: 'oas.yaml#/components/responses/401'
|
$ref: 'oas.yaml#/components/responses/404'
|
||||||
500:
|
500:
|
||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
26
package-lock.json
generated
26
package-lock.json
generated
@ -203,6 +203,14 @@
|
|||||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||||
"dev": true
|
"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": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
@ -848,6 +856,24 @@
|
|||||||
"is-buffer": "~2.0.3"
|
"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": {
|
"form-data": {
|
||||||
"version": "2.5.1",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@hapi/joi": "^17.1.1",
|
"@hapi/joi": "^17.1.1",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "^13.1.6",
|
"@types/node": "^13.1.6",
|
||||||
|
"axios": "^0.19.2",
|
||||||
"basic-auth": "^2.0.1",
|
"basic-auth": "^2.0.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
|
@ -51,6 +51,7 @@ export default class db {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
mongoose.connection.once('open', () => {
|
mongoose.connection.once('open', () => {
|
||||||
|
mongoose.set('useFindAndModify', false);
|
||||||
console.log(process.env.NODE_ENV === 'test' ? '' : `Connected to ${connectionString}`);
|
console.log(process.env.NODE_ENV === 'test' ? '' : `Connected to ${connectionString}`);
|
||||||
this.state.db = mongoose.connection;
|
this.state.db = mongoose.connection;
|
||||||
done();
|
done();
|
||||||
|
64
src/helpers/mail.ts
Normal file
64
src/helpers/mail.ts
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -106,3 +106,95 @@ describe('/user/new', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -3,6 +3,7 @@ import mongoose from 'mongoose';
|
|||||||
import bcrypt from 'bcryptjs';
|
import bcrypt from 'bcryptjs';
|
||||||
import UserValidate from './validate/user';
|
import UserValidate from './validate/user';
|
||||||
import UserModel from '../models/user';
|
import UserModel from '../models/user';
|
||||||
|
import mail from '../helpers/mail';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -11,7 +12,6 @@ router.get('/users', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.post('/user/new', (req, res, next) => {
|
router.post('/user/new', (req, res, next) => {
|
||||||
console.log(req.authDetails);
|
|
||||||
if (!req.auth(res, ['admin'], 'basic')) return;
|
if (!req.auth(res, ['admin'], 'basic')) return;
|
||||||
|
|
||||||
// validate input
|
// 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;
|
module.exports = router;
|
Reference in New Issue
Block a user