1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: Add change-password endpoint to user-controller (#800)

fixes: #801 

Co-authored-by: Fredrik Oseberg <fredrik.no@gmail.com>
This commit is contained in:
Christopher Kolstad 2021-04-22 16:05:59 +02:00 committed by GitHub
parent 185091174f
commit 18f66ef732
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 21 deletions

View File

@ -4,7 +4,7 @@
},
"extends": [
"airbnb-typescript/base",
"prettier",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {

View File

@ -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);
});

View File

@ -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<PARAM, QUERY, BODY, RESPONSE>
extends Request<PARAM, QUERY, BODY, RESPONSE> {
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<IUnleashServices, 'accessService' | 'userService'>,
) {
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<void> {
@ -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<any, any, IChangeUserRequest, any>,
res: Response,
): Promise<void> {
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}/`);
}
}