diff --git a/.eslintrc b/.eslintrc
index bf48f61c49..1218df91cb 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -4,7 +4,7 @@
},
"extends": [
"airbnb-typescript/base",
- "prettier",
+ "prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
diff --git a/src/lib/routes/admin-api/user.test.js b/src/lib/routes/admin-api/user.test.js
index 315a0821ff..90214832b8 100644
--- a/src/lib/routes/admin-api/user.test.js
+++ b/src/lib/routes/admin-api/user.test.js
@@ -17,6 +17,8 @@ const currentUser = new User({ email: 'test@mail.com' });
function getSetup() {
const base = `/random${Math.round(Math.random() * 1000)}`;
const stores = store.createStores();
+ stores.userStore.insert(currentUser);
+
const config = createTestConfig({
preHook: a => {
a.use((req, res, next) => {
@@ -30,12 +32,12 @@ function getSetup() {
const app = getApp(config, stores, services, eventBus);
return {
base,
- strategyStore: stores.strategyStore,
+ userStore: stores.userStore,
request: supertest(app),
};
}
-test.only('should return current user', t => {
+test('should return current user', t => {
t.plan(1);
const { request, base } = getSetup();
@@ -47,13 +49,35 @@ test.only('should return current user', t => {
t.is(res.body.user.email, currentUser.email);
});
});
+const owaspPassword = 't7GTx&$Y9pcsnxRv6';
-test('should logout and redirect', t => {
+test('should allow user to change password', async t => {
+ t.plan(2);
+ const { request, base, userStore } = getSetup();
+ const before = await userStore.get(currentUser);
+ t.falsy(before.passwordHash);
+ await request
+ .post(`${base}/api/admin/user/change-password`)
+ .send({ password: owaspPassword, confirmPassword: owaspPassword })
+ .expect(200);
+ const updated = await userStore.get(currentUser);
+ t.truthy(updated.passwordHash);
+});
+
+test('should deny if password and confirmPassword are not equal', async t => {
t.plan(0);
const { request, base } = getSetup();
-
return request
- .get(`${base}/api/admin/user/logout`)
- .expect(302)
- .expect('Location', `${base}/`);
+ .post(`${base}/api/admin/user/change-password`)
+ .send({ password: owaspPassword, confirmPassword: 'somethingelse' })
+ .expect(400);
+});
+
+test('should deny if password does not fulfill owasp criteria', async t => {
+ t.plan(0);
+ const { request, base } = getSetup();
+ return request
+ .post(`${base}/api/admin/user/change-password`)
+ .send({ password: 'hunter123', confirmPassword: 'hunter123' })
+ .expect(400);
});
diff --git a/src/lib/routes/admin-api/user.ts b/src/lib/routes/admin-api/user.ts
index d4e4fd7bef..3d04a375e3 100644
--- a/src/lib/routes/admin-api/user.ts
+++ b/src/lib/routes/admin-api/user.ts
@@ -1,24 +1,47 @@
'use strict';
-import { Response } from 'express';
+import { Request, Response } from 'express';
import { IAuthRequest } from '../unleash-types';
import Controller from '../controller';
import { AccessService } from '../../services/access-service';
import { IUnleashConfig } from '../../types/option';
+import { IUnleashServices } from '../../types/services';
+import UserService from '../../services/user-service';
+import User from '../../user';
+import { Logger } from '../../logger';
+import { handleErrors } from './util';
-interface IService {
- accessService: AccessService;
+interface IChangeUserRequest {
+ password: string;
+ confirmPassword: string;
+}
+
+interface UserRequest
+ extends Request {
+ user: User;
}
class UserController extends Controller {
private accessService: AccessService;
- constructor(config: IUnleashConfig, { accessService }: IService) {
+ private userService: UserService;
+
+ private logger: Logger;
+
+ constructor(
+ config: IUnleashConfig,
+ {
+ accessService,
+ userService,
+ }: Pick,
+ ) {
super(config);
this.accessService = accessService;
+ this.userService = userService;
+ this.logger = config.getLogger('lib/routes/admin-api/user.ts');
this.get('/', this.getUser);
- this.get('/logout', this.logout);
+ this.post('/change-password', this.updateUserPass);
}
async getUser(req: IAuthRequest, res: Response): Promise {
@@ -36,15 +59,27 @@ class UserController extends Controller {
return res.status(404).end();
}
- // Deprecated, use "/logout" instead. Will be removed in v4.
- logout(req: IAuthRequest, res: Response): void {
- if (req.session) {
- req.session = null;
+ async updateUserPass(
+ req: UserRequest,
+ res: Response,
+ ): Promise {
+ const { user } = req;
+ if (user) {
+ const { password, confirmPassword } = req.body;
+ try {
+ if (password === confirmPassword) {
+ this.userService.validatePassword(password);
+ await this.userService.changePassword(user.id, password);
+ res.status(200).end();
+ } else {
+ res.status(400).end();
+ }
+ } catch (e) {
+ handleErrors(res, this.logger, e);
+ }
+ } else {
+ res.status(401).end();
}
- if (req.logout) {
- req.logout();
- }
- res.redirect(`${this.config.server.baseUriPath}/`);
}
}