diff --git a/oas/schemas.yaml b/oas/schemas.yaml
index 82c9508..d4151d1 100644
--- a/oas/schemas.yaml
+++ b/oas/schemas.yaml
@@ -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
diff --git a/oas/user.yaml b/oas/user.yaml
index 3db2b3c..4042901 100644
--- a/oas/user.yaml
+++ b/oas/user.yaml
@@ -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'
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 795376c..b8354bc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 7630a0c..d5a2bfe 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/db.ts b/src/db.ts
index de45a74..b93fb6f 100644
--- a/src/db.ts
+++ b/src/db.ts
@@ -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();
diff --git a/src/helpers/mail.ts b/src/helpers/mail.ts
new file mode 100644
index 0000000..949d243
--- /dev/null
+++ b/src/helpers/mail.ts
@@ -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);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/routes/user.spec.ts b/src/routes/user.spec.ts
index f78d387..a6ebec0 100644
--- a/src/routes/user.spec.ts
+++ b/src/routes/user.spec.ts
@@ -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();
+ });
+ });
+ });
+ });
});
\ No newline at end of file
diff --git a/src/routes/user.ts b/src/routes/user.ts
index ffaebc7..e4a17d5 100644
--- a/src/routes/user.ts
+++ b/src/routes/user.ts
@@ -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,
You requested to reset your password.
Your new password is:
' + newPass + '
If you did not request a password reset, talk to the sysadmin quickly!
Have a nice day.
The DFOP team', err => {
+ if (err) next(err);
+ res.json({status: 'OK'});
+ });
+ });
+ });
+ }
+ else {
+ res.status(404).json({status: 'Not found'});
+ }
+ });
+});
+
module.exports = router;
\ No newline at end of file