1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-10-18 20:09:08 +02:00
unleash.unleash/src/lib/services/reset-token-service.ts

127 lines
3.6 KiB
TypeScript
Raw Normal View History

import crypto from 'crypto';
2022-01-06 20:43:57 +01:00
import bcrypt from 'bcryptjs';
import { URL } from 'url';
import { Logger } from '../logger';
import UsedTokenError from '../error/used-token-error';
import InvalidTokenError from '../error/invalid-token-error';
import { IUnleashConfig } from '../types/option';
import { IUnleashStores } from '../types/stores';
import {
IResetQuery,
IResetToken,
IResetTokenStore,
} from '../types/stores/reset-token-store';
import { hoursToMilliseconds } from 'date-fns';
interface IInviteLinks {
[key: string]: string;
}
export default class ResetTokenService {
private store: IResetTokenStore;
private logger: Logger;
2021-05-11 14:43:41 +02:00
private readonly unleashBase: string;
constructor(
{ resetTokenStore }: Pick<IUnleashStores, 'resetTokenStore'>,
{ getLogger, server }: Pick<IUnleashConfig, 'getLogger' | 'server'>,
) {
this.store = resetTokenStore;
this.logger = getLogger('/services/reset-token-service.ts');
2021-05-11 14:43:41 +02:00
this.unleashBase = server.unleashUrl;
}
async useAccessToken(token: IResetQuery): Promise<boolean> {
try {
await this.isValid(token.token);
await this.store.useToken(token);
return true;
} catch (e) {
return false;
}
}
async getActiveInvitations(): Promise<IInviteLinks> {
try {
const tokens = await this.store.getActiveTokens();
const links = tokens.reduce((acc, token) => {
const inviteLink =
this.getExistingInvitationUrl(token).toString();
acc[token.userId] = inviteLink;
return acc;
}, {});
return links;
} catch (e) {
return {};
}
}
async isValid(token: string): Promise<IResetToken> {
let t;
try {
t = await this.store.getActive(token);
if (!t.usedAt) {
return t;
}
} catch (e) {
throw new InvalidTokenError();
}
throw new UsedTokenError(t.usedAt);
}
private getExistingInvitationUrl(token: IResetToken) {
2021-05-11 14:43:41 +02:00
return new URL(`${this.unleashBase}/new-user?token=${token.token}`);
}
private async createResetUrl(
forUser: number,
creator: string,
path: string,
): Promise<URL> {
const token = await this.createToken(forUser, creator);
return Promise.resolve(
2021-05-11 14:43:41 +02:00
new URL(`${this.unleashBase}${path}?token=${token.token}`),
);
}
async createResetPasswordUrl(
forUser: number,
creator: string,
): Promise<URL> {
const path = '/reset-password';
return this.createResetUrl(forUser, creator, path);
}
async createNewUserUrl(forUser: number, creator: string): Promise<URL> {
const path = '/new-user';
return this.createResetUrl(forUser, creator, path);
}
async createToken(
tokenUser: number,
creator: string,
expiryDelta: number = hoursToMilliseconds(24),
): Promise<IResetToken> {
const token = await this.generateToken();
const expiry = new Date(Date.now() + expiryDelta);
await this.store.expireExistingTokensForUser(tokenUser);
return this.store.insert({
reset_token: token,
user_id: tokenUser,
expires_at: expiry,
created_by: creator,
});
}
private generateToken(): Promise<string> {
2022-01-06 20:43:57 +01:00
return bcrypt.hash(crypto.randomBytes(32).toString(), 10);
}
}
module.exports = ResetTokenService;