Skip to content

Commit

Permalink
fix: welcome-email should not include password-link when disabled (#1302
Browse files Browse the repository at this point in the history
)
  • Loading branch information
ivarconr committed Jan 28, 2022
1 parent 26f66c4 commit 1cad01b
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 59 deletions.
68 changes: 39 additions & 29 deletions src/lib/routes/admin-api/user-admin.ts
Expand Up @@ -10,6 +10,9 @@ import ResetTokenService from '../../services/reset-token-service';
import { IUnleashServices } from '../../types/services';
import SessionService from '../../services/session-service';
import { IAuthRequest } from '../unleash-types';
import SettingService from '../../services/setting-service';
import { SimpleAuthSettings } from '../../server-impl';
import { simpleAuthKey } from '../../types/settings/simple-auth-settings';

interface ICreateUserBody {
username: string;
Expand All @@ -32,6 +35,10 @@ export default class UserAdminController extends Controller {

private sessionService: SessionService;

private settingService: SettingService;

readonly unleashUrl: string;

constructor(
config: IUnleashConfig,
{
Expand All @@ -40,22 +47,26 @@ export default class UserAdminController extends Controller {
emailService,
resetTokenService,
sessionService,
settingService,
}: Pick<
IUnleashServices,
| 'userService'
| 'accessService'
| 'emailService'
| 'resetTokenService'
| 'sessionService'
| 'settingService'
>,
) {
super(config);
this.userService = userService;
this.accessService = accessService;
this.emailService = emailService;
this.logger = config.getLogger('routes/user-controller.ts');
this.resetTokenService = resetTokenService;
this.sessionService = sessionService;
this.settingService = settingService;
this.logger = config.getLogger('routes/user-controller.ts');
this.unleashUrl = config.server.unleashUrl;

this.get('/', this.getUsers, ADMIN);
this.get('/search', this.search);
Expand All @@ -69,41 +80,32 @@ export default class UserAdminController extends Controller {
this.get('/active-sessions', this.getActiveSessions, ADMIN);
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async resetPassword(req, res): Promise<void> {
async resetPassword(req: IAuthRequest, res: Response): Promise<void> {
const { user } = req;
const receiver = req.body.id;
const resetPasswordUrl =
await this.userService.createResetPasswordEmail(receiver, user);
res.json({ resetPasswordUrl });
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async getUsers(req: Request, res: Response): Promise<void> {
try {
const users = await this.userService.getAll();
const rootRoles = await this.accessService.getRootRoles();
const inviteLinks =
await this.resetTokenService.getActiveInvitations();

const usersWithInviteLinks = users.map((user) => {
const inviteLink = inviteLinks[user.id] || '';
return { ...user, inviteLink };
});
const users = await this.userService.getAll();
const rootRoles = await this.accessService.getRootRoles();
const inviteLinks = await this.resetTokenService.getActiveInvitations();

res.json({ users: usersWithInviteLinks, rootRoles });
} catch (error) {
this.logger.error(error);
res.status(500).send({ msg: 'server errors' });
}
const usersWithInviteLinks = users.map((user) => {
const inviteLink = inviteLinks[user.id] || '';
return { ...user, inviteLink };
});

res.json({ users: usersWithInviteLinks, rootRoles });
}

async getActiveSessions(req: Request, res: Response): Promise<void> {
const sessions = await this.sessionService.getActiveSessions();
res.json(sessions);
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async search(req: Request, res: Response): Promise<void> {
const { q } = req.query as any;
try {
Expand All @@ -122,7 +124,6 @@ export default class UserAdminController extends Controller {
res.json(user);
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
async createUser(
req: IAuthRequest<any, any, ICreateUserBody, any>,
res: Response,
Expand All @@ -140,10 +141,20 @@ export default class UserAdminController extends Controller {
},
user,
);
const inviteLink = await this.resetTokenService.createNewUserUrl(
createdUser.id,
user.email,
);

const passwordAuthSettings =
await this.settingService.get<SimpleAuthSettings>(
simpleAuthKey,
);

let inviteLink: string;
if (!passwordAuthSettings?.disabled) {
const inviteUrl = await this.resetTokenService.createNewUserUrl(
createdUser.id,
user.email,
);
inviteLink = inviteUrl.toString();
}

let emailSent = false;
const emailConfigured = this.emailService.configured();
Expand All @@ -154,7 +165,8 @@ export default class UserAdminController extends Controller {
await this.emailService.sendGettingStartedMail(
createdUser.name,
createdUser.email,
inviteLink.toString(),
this.unleashUrl,
inviteLink,
);
emailSent = true;
} catch (e) {
Expand All @@ -171,7 +183,7 @@ export default class UserAdminController extends Controller {

res.status(201).send({
...createdUser,
inviteLink,
inviteLink: inviteLink || this.unleashUrl,
emailSent,
rootRole,
});
Expand Down Expand Up @@ -227,5 +239,3 @@ export default class UserAdminController extends Controller {
res.status(200).send();
}
}

module.exports = UserAdminController;
27 changes: 0 additions & 27 deletions src/lib/routes/auth/simple-password-provider.js

This file was deleted.

3 changes: 3 additions & 0 deletions src/lib/routes/auth/simple-password-provider.test.ts
Expand Up @@ -9,6 +9,7 @@ test('Should require password', async () => {
const app = express();
app.use(express.json());
const userService = () => {};
// @ts-ignore
const ctr = new PasswordProvider({ getLogger }, { userService });

//@ts-ignore
Expand Down Expand Up @@ -41,6 +42,7 @@ test('Should login user', async () => {
throw new Error('Wrong password');
},
};
// @ts-ignore
const ctr = new PasswordProvider({ getLogger }, { userService });

//@ts-ignore
Expand Down Expand Up @@ -74,6 +76,7 @@ test('Should not login user with wrong password', async () => {
throw new PasswordMismatchError();
},
};
// @ts-ignore
const ctr = new PasswordProvider({ getLogger }, { userService });

//@ts-ignore
Expand Down
42 changes: 42 additions & 0 deletions src/lib/routes/auth/simple-password-provider.ts
@@ -0,0 +1,42 @@
import { Response } from 'express';
import { Logger } from '../../logger';
import { IUnleashConfig } from '../../server-impl';
import UserService from '../../services/user-service';
import { IUnleashServices } from '../../types';
import { NONE } from '../../types/permissions';
import Controller from '../controller';
import { IAuthRequest } from '../unleash-types';

class PasswordProvider extends Controller {
private userService: UserService;

private logger: Logger;

constructor(
config: IUnleashConfig,
{ userService }: Pick<IUnleashServices, 'userService'>,
) {
super(config);
this.logger = config.getLogger('/auth/password-provider.js');
this.userService = userService;

this.post('/login', this.login, NONE);
}

async login(req: IAuthRequest, res: Response): Promise<void> {
const { username, password } = req.body;

if (!username || !password) {
res.status(400).json({
message: 'You must provide username and password',
});
return;
}

const user = await this.userService.loginUser(username, password);
req.session.user = user;
res.status(200).json(user);
}
}

export default PasswordProvider;
2 changes: 1 addition & 1 deletion src/lib/routes/index.ts
@@ -1,6 +1,7 @@
import { Request, Response } from 'express';
import { BackstageController } from './backstage';
import ResetPasswordController from './auth/reset-password-controller';
import SimplePasswordProvider from './auth/simple-password-provider';
import { IUnleashConfig } from '../types/option';
import { IUnleashServices } from '../types/services';
import { api } from './api-def';
Expand All @@ -10,7 +11,6 @@ const ClientApi = require('./client-api');
const Controller = require('./controller');
const HealthCheckController = require('./health-check');
const LogoutController = require('./logout');
const SimplePasswordProvider = require('./auth/simple-password-provider');

class IndexRouter extends Controller {
constructor(config: IUnleashConfig, services: IUnleashServices) {
Expand Down
5 changes: 3 additions & 2 deletions src/lib/services/email-service.ts
Expand Up @@ -136,11 +136,12 @@ export class EmailService {
async sendGettingStartedMail(
name: string,
recipient: string,
passwordLink: string,
unleashUrl: string,
passwordLink?: string,
): Promise<IEmailEnvelope> {
if (this.configured()) {
const year = new Date().getFullYear();
const context = { passwordLink, name, year };
const context = { passwordLink, name, year, unleashUrl };
const bodyHtml = await this.compileTemplate(
'getting-started',
TemplateFormat.HTML,
Expand Down
Expand Up @@ -484,10 +484,18 @@
<p>You have been invited to your organization's Unleash account - the new way of delivering software.</p>
{{# passwordLink }}
<p>Below is your magic sign-in link. Just click the button and follow the steps provided to update your password and get started using Unleash.</p>
<br />
<a class="resetPasswordLink" href="{{{ passwordLink }}}" target="_blank" rel="noopener noreferrer">Setup account<a/>
{{/ passwordLink }}
{{^ passwordLink }}
<p>Use the link below to access your Unleash instance.</p>
<br />
<a class="resetPasswordLink" href="{{{ unleashUrl }}}" target="_blank" rel="noopener noreferrer">Login<a/>
{{/ passwordLink }}
<br />
<br />
<p>By the way - did you know we have built Unleash on best practice when releasing new features. Our solution removes pressure from developers, allowing you to focus on delivering value through experimentation.</p>
Expand Down
10 changes: 10 additions & 0 deletions src/mailtemplates/getting-started/getting-started.plain.mustache
Expand Up @@ -2,9 +2,19 @@ Welcome to Unleash {{ name }}!

You have been invited to your organization's Unleash account - the new way of delivering software.

{{# passwordLink }}

Below is your magic sign-in link. Just click the button and follow the steps provided to update your password and get started using Unleash.

Visit {{{ passwordLink }}} to get started.
{{/ passwordLink }}
{{^ passwordLink }}

Use the link below to access your Unleash instance:

{{{ unleashUrl }}}

{{/ passwordLink }}

By the way - did you know we have built Unleash on best practice when releasing new features. Our solution removes pressure from developers, allowing you to focus on delivering value through experimentation.
Looking forward to having a lot of fun together.
Expand Down

0 comments on commit 1cad01b

Please sign in to comment.