hedgedoc/src/users/users.service.ts
Philip Molares 4784a1aea2
private: Add until to token creation
Signed-off-by: Philip Molares <philip.molares@udo.edu>
2021-01-21 12:33:45 +01:00

150 lines
4.5 KiB
TypeScript

/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { NotInDBError } from '../errors/errors';
import { ConsoleLoggerService } from '../logger/console-logger.service';
import { UserInfoDto } from './user-info.dto';
import { User } from './user.entity';
import { AuthToken } from './auth-token.entity';
import { hash, compare } from 'bcrypt'
import crypt from 'crypto';
import { AuthTokenDto } from './auth-token.dto';
import { AuthTokenWithSecretDto } from './auth-token-with-secret.dto';
@Injectable()
export class UsersService {
constructor(
private readonly logger: ConsoleLoggerService,
@InjectRepository(User) private userRepository: Repository<User>,
@InjectRepository(AuthToken)
private authTokenRepository: Repository<AuthToken>,
) {
this.logger.setContext(UsersService.name);
}
createUser(userName: string, displayName: string): Promise<User> {
const user = User.create(userName, displayName);
return this.userRepository.save(user);
}
async createTokenForUser(
userName: string,
identifier: string,
until: number,
): Promise<AuthToken> {
const user = await this.getUserByUsername(userName);
const randomString = crypt.randomBytes(64).toString('base64url');
const accessToken = await this.hashPassword(randomString);
const token = AuthToken.create(user, identifier, accessToken, new Date(until));
const createdToken = await this.authTokenRepository.save(token);
return {
accessToken: randomString,
...createdToken,
};
}
async deleteUser(userName: string) {
// TODO: Handle owned notes and edits
const user = await this.userRepository.findOne({
where: { userName: userName },
});
await this.userRepository.delete(user);
}
async getUserByUsername(userName: string): Promise<User> {
const user = await this.userRepository.findOne({
where: { userName: userName },
});
if (user === undefined) {
throw new NotInDBError(`User with username '${userName}' not found`);
}
return user;
}
async hashPassword(cleartext: string): Promise<string> {
// hash the password with bcrypt and 2^16 iterations
return hash(cleartext, 16)
}
async checkPassword(cleartext: string, password: string): Promise<boolean> {
// hash the password with bcrypt and 2^16 iterations
return compare(cleartext, password)
}
async getUserByAuthToken(token: string): Promise<User> {
const hash = this.hashPassword(token);
const accessToken = await this.authTokenRepository.findOne({
where: { accessToken: hash },
});
if (accessToken === undefined) {
throw new NotInDBError(`AuthToken '${token}' not found`);
}
return this.getUserByUsername(accessToken.user.userName);
}
getPhotoUrl(user: User): string {
if (user.photo) {
return user.photo;
} else {
// TODO: Create new photo, see old code
return '';
}
}
async getTokensByUsername(userName: string): Promise<AuthToken[]> {
const user = await this.getUserByUsername(userName);
return user.authTokens;
}
async removeToken(userName: string, timestamp: number) {
const user = await this.getUserByUsername(userName);
const token = await this.authTokenRepository.findOne({
where: { createdAt: new Date(timestamp), user: user },
});
await this.authTokenRepository.remove(token);
}
toAuthTokenDto(authToken: AuthToken | null | undefined): AuthTokenDto | null {
if (!authToken) {
this.logger.warn(`Recieved ${authToken} argument!`, 'toAuthTokenDto');
return null;
}
return {
label: authToken.identifier,
created: authToken.createdAt.getTime(),
};
}
toAuthTokenWithSecretDto(
authToken: AuthToken | null | undefined,
): AuthTokenWithSecretDto | null {
if (!authToken) {
this.logger.warn(`Recieved ${authToken} argument!`, 'toAuthTokenDto');
return null;
}
return {
label: authToken.identifier,
created: authToken.createdAt.getTime(),
secret: authToken.accessToken,
};
}
toUserDto(user: User | null | undefined): UserInfoDto | null {
if (!user) {
this.logger.warn(`Recieved ${user} argument!`, 'toUserDto');
return null;
}
return {
userName: user.userName,
displayName: user.displayName,
photo: this.getPhotoUrl(user),
email: user.email,
};
}
}