mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-21 18:55:19 -04:00
chore: move password related functions from AuthService to utils file
As these methods will be used in both the AuthService and the IdentityService, it makes sense to extract them and use them in this manner. Especially if one considers that they are quite standalone functions. Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
parent
4938d308b0
commit
87a5f77abe
4 changed files with 109 additions and 63 deletions
|
@ -6,7 +6,6 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Cron, Timeout } from '@nestjs/schedule';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { compare, hash } from 'bcrypt';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
|
@ -16,8 +15,13 @@ import {
|
|||
TooManyTokensError,
|
||||
} from '../errors/errors';
|
||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { UserRelationEnum } from '../users/user-relation.enum';
|
||||
import { User } from '../users/user.entity';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import {
|
||||
bufferToBase64Url,
|
||||
hashPassword,
|
||||
} from '../utils/password';
|
||||
import { TimestampMillis } from '../utils/timestamp';
|
||||
import { AuthTokenWithSecretDto } from './auth-token-with-secret.dto';
|
||||
import { AuthTokenDto } from './auth-token.dto';
|
||||
|
@ -52,33 +56,14 @@ export class AuthService {
|
|||
return await this.usersService.getUserByUsername(accessToken.user.userName);
|
||||
}
|
||||
|
||||
async hashPassword(cleartext: string): Promise<string> {
|
||||
// hash the password with bcrypt and 2^12 iterations
|
||||
// this was decided on the basis of https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#bcrypt
|
||||
return await hash(cleartext, 12);
|
||||
}
|
||||
|
||||
async checkPassword(cleartext: string, password: string): Promise<boolean> {
|
||||
return await compare(cleartext, password);
|
||||
}
|
||||
|
||||
bufferToBase64Url(text: Buffer): string {
|
||||
// This is necessary as the is no base64url encoding in the toString method
|
||||
// but as can be seen on https://tools.ietf.org/html/rfc4648#page-7
|
||||
// base64url is quite easy buildable from base64
|
||||
return text
|
||||
.toString('base64')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=+$/, '');
|
||||
}
|
||||
|
||||
async createTokenForUser(
|
||||
userName: string,
|
||||
identifier: string,
|
||||
validUntil: TimestampMillis,
|
||||
): Promise<AuthTokenWithSecretDto> {
|
||||
const user = await this.usersService.getUserByUsername(userName, true);
|
||||
const user = await this.usersService.getUserByUsername(userName, [
|
||||
UserRelationEnum.AUTHTOKENS,
|
||||
]);
|
||||
if (user.authTokens.length >= 200) {
|
||||
// This is a very high ceiling unlikely to hinder legitimate usage,
|
||||
// but should prevent possible attack vectors
|
||||
|
@ -86,9 +71,9 @@ export class AuthService {
|
|||
`User '${user.userName}' has already 200 tokens and can't have anymore`,
|
||||
);
|
||||
}
|
||||
const secret = this.bufferToBase64Url(randomBytes(54));
|
||||
const keyId = this.bufferToBase64Url(randomBytes(8));
|
||||
const accessToken = await this.hashPassword(secret);
|
||||
const secret = bufferToBase64Url(randomBytes(54));
|
||||
const keyId = bufferToBase64Url(randomBytes(8));
|
||||
const accessToken = await hashPassword(secret);
|
||||
let token;
|
||||
// Tokens can only be valid for a maximum of 2 years
|
||||
const maximumTokenValidity =
|
||||
|
@ -138,7 +123,7 @@ export class AuthService {
|
|||
if (accessToken === undefined) {
|
||||
throw new NotInDBError(`AuthToken '${token}' not found`);
|
||||
}
|
||||
if (!(await this.checkPassword(token, accessToken.accessTokenHash))) {
|
||||
if (!(await checkPassword(token, accessToken.accessTokenHash))) {
|
||||
// hashes are not the same
|
||||
throw new TokenNotValidError(`AuthToken '${token}' is not valid.`);
|
||||
}
|
||||
|
@ -155,7 +140,9 @@ export class AuthService {
|
|||
}
|
||||
|
||||
async getTokensByUsername(userName: string): Promise<AuthToken[]> {
|
||||
const user = await this.usersService.getUserByUsername(userName, true);
|
||||
const user = await this.usersService.getUserByUsername(userName, [
|
||||
UserRelationEnum.AUTHTOKENS,
|
||||
]);
|
||||
if (user.authTokens === undefined) {
|
||||
return [];
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue