mirror of
https://github.com/Shadowfita/docmost.git
synced 2025-11-19 03:01:10 +10:00
Refactoring
* replace TypeORM with Kysely query builder * refactor migrations * other changes and fixes
This commit is contained in:
@ -1,8 +0,0 @@
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
export async function comparePasswordHash(
|
||||
plainPassword: string,
|
||||
passwordHash: string,
|
||||
): Promise<boolean> {
|
||||
return bcrypt.compare(plainPassword, passwordHash);
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
import { CanActivate, ForbiddenException, Injectable } from '@nestjs/common';
|
||||
import { WorkspaceRepository } from '../../workspace/repositories/workspace.repository';
|
||||
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||
|
||||
@Injectable()
|
||||
export class SetupGuard implements CanActivate {
|
||||
constructor(private workspaceRepository: WorkspaceRepository) {}
|
||||
constructor(private workspaceRepo: WorkspaceRepo) {}
|
||||
|
||||
async canActivate(): Promise<boolean> {
|
||||
const workspaceCount = await this.workspaceRepository.count();
|
||||
const workspaceCount = await this.workspaceRepo.count();
|
||||
if (workspaceCount > 0) {
|
||||
throw new ForbiddenException('Workspace setup already completed.');
|
||||
}
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { LoginDto } from '../dto/login.dto';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { CreateUserDto } from '../dto/create-user.dto';
|
||||
import { UserService } from '../../user/user.service';
|
||||
import { TokenService } from './token.service';
|
||||
import { TokensDto } from '../dto/tokens.dto';
|
||||
import { UserRepository } from '../../user/repositories/user.repository';
|
||||
import { comparePasswordHash } from '../auth.utils';
|
||||
import { SignupService } from './signup.service';
|
||||
import { CreateAdminUserDto } from '../dto/create-admin-user.dto';
|
||||
import { UserRepo } from '@docmost/db/repos/user/user.repo';
|
||||
import { comparePasswordHash } from '../../../helpers/utils';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
@ -16,14 +15,11 @@ export class AuthService {
|
||||
private userService: UserService,
|
||||
private signupService: SignupService,
|
||||
private tokenService: TokenService,
|
||||
private userRepository: UserRepository,
|
||||
private userRepo: UserRepo,
|
||||
) {}
|
||||
|
||||
async login(loginDto: LoginDto, workspaceId: string) {
|
||||
const user = await this.userRepository.findOneByEmail(
|
||||
loginDto.email,
|
||||
workspaceId,
|
||||
);
|
||||
const user = await this.userRepo.findByEmail(loginDto.email, workspaceId);
|
||||
|
||||
if (
|
||||
!user ||
|
||||
@ -33,17 +29,14 @@ export class AuthService {
|
||||
}
|
||||
|
||||
user.lastLoginAt = new Date();
|
||||
await this.userRepository.save(user);
|
||||
await this.userRepo.updateLastLogin(user.id, workspaceId);
|
||||
|
||||
const tokens: TokensDto = await this.tokenService.generateTokens(user);
|
||||
return { tokens };
|
||||
}
|
||||
|
||||
async register(createUserDto: CreateUserDto, workspaceId: string) {
|
||||
const user: User = await this.signupService.signup(
|
||||
createUserDto,
|
||||
workspaceId,
|
||||
);
|
||||
const user = await this.signupService.signup(createUserDto, workspaceId);
|
||||
|
||||
const tokens: TokensDto = await this.tokenService.generateTokens(user);
|
||||
|
||||
@ -51,8 +44,7 @@ export class AuthService {
|
||||
}
|
||||
|
||||
async setup(createAdminUserDto: CreateAdminUserDto) {
|
||||
const user: User =
|
||||
await this.signupService.initialSetup(createAdminUserDto);
|
||||
const user = await this.signupService.initialSetup(createAdminUserDto);
|
||||
|
||||
const tokens: TokensDto = await this.tokenService.generateTokens(user);
|
||||
|
||||
|
||||
@ -1,140 +1,95 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { CreateUserDto } from '../dto/create-user.dto';
|
||||
import { DataSource, EntityManager } from 'typeorm';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { transactionWrapper } from '../../../helpers/db.helper';
|
||||
import { UserRepository } from '../../user/repositories/user.repository';
|
||||
import { WorkspaceRepository } from '../../workspace/repositories/workspace.repository';
|
||||
import { WorkspaceService } from '../../workspace/services/workspace.service';
|
||||
import { CreateWorkspaceDto } from '../../workspace/dto/create-workspace.dto';
|
||||
import { Workspace } from '../../workspace/entities/workspace.entity';
|
||||
import { SpaceService } from '../../space/services/space.service';
|
||||
import { CreateAdminUserDto } from '../dto/create-admin-user.dto';
|
||||
import { GroupUserService } from '../../group/services/group-user.service';
|
||||
import { UserRepo } from '@docmost/db/repos/user/user.repo';
|
||||
import { KyselyDB, KyselyTransaction } from '@docmost/db/types/kysely.types';
|
||||
import { executeTx } from '@docmost/db/utils';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { User } from '@docmost/db/types/entity.types';
|
||||
|
||||
@Injectable()
|
||||
export class SignupService {
|
||||
constructor(
|
||||
private userRepository: UserRepository,
|
||||
private workspaceRepository: WorkspaceRepository,
|
||||
private userRepo: UserRepo,
|
||||
private workspaceService: WorkspaceService,
|
||||
private spaceService: SpaceService,
|
||||
private groupUserService: GroupUserService,
|
||||
private dataSource: DataSource,
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
) {}
|
||||
|
||||
prepareUser(createUserDto: CreateUserDto): User {
|
||||
const user = new User();
|
||||
user.name = createUserDto.name || createUserDto.email.split('@')[0];
|
||||
user.email = createUserDto.email.toLowerCase();
|
||||
user.password = createUserDto.password;
|
||||
user.locale = 'en';
|
||||
user.lastLoginAt = new Date();
|
||||
return user;
|
||||
}
|
||||
|
||||
async createUser(
|
||||
createUserDto: CreateUserDto,
|
||||
manager?: EntityManager,
|
||||
): Promise<User> {
|
||||
return await transactionWrapper(
|
||||
async (transactionManager: EntityManager) => {
|
||||
let user = this.prepareUser(createUserDto);
|
||||
user = await transactionManager.save(user);
|
||||
return user;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
);
|
||||
}
|
||||
|
||||
async signup(
|
||||
createUserDto: CreateUserDto,
|
||||
workspaceId: string,
|
||||
manager?: EntityManager,
|
||||
trx?: KyselyTransaction,
|
||||
): Promise<User> {
|
||||
const userCheck = await this.userRepository.findOneByEmail(
|
||||
const userCheck = await this.userRepo.findByEmail(
|
||||
createUserDto.email,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (userCheck) {
|
||||
throw new BadRequestException(
|
||||
'You already have an account on this workspace',
|
||||
);
|
||||
}
|
||||
|
||||
return await transactionWrapper(
|
||||
async (manager: EntityManager) => {
|
||||
return await executeTx(
|
||||
this.db,
|
||||
async (trx) => {
|
||||
// create user
|
||||
const user = await this.createUser(createUserDto, manager);
|
||||
const user = await this.userRepo.insertUser(createUserDto, trx);
|
||||
|
||||
// add user to workspace
|
||||
await this.workspaceService.addUserToWorkspace(
|
||||
user,
|
||||
user.id,
|
||||
workspaceId,
|
||||
undefined,
|
||||
manager,
|
||||
trx,
|
||||
);
|
||||
|
||||
// add user to default group
|
||||
await this.groupUserService.addUserToDefaultGroup(
|
||||
user.id,
|
||||
workspaceId,
|
||||
manager,
|
||||
trx,
|
||||
);
|
||||
|
||||
return user;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
async createWorkspace(
|
||||
user: User,
|
||||
workspaceName,
|
||||
manager?: EntityManager,
|
||||
): Promise<Workspace> {
|
||||
return await transactionWrapper(
|
||||
async (manager: EntityManager) => {
|
||||
// for cloud
|
||||
async createWorkspace(user, workspaceName, trx?: KyselyTransaction) {
|
||||
return await executeTx(
|
||||
this.db,
|
||||
async (trx) => {
|
||||
const workspaceData: CreateWorkspaceDto = {
|
||||
name: workspaceName,
|
||||
// hostname: '', // generate
|
||||
};
|
||||
|
||||
return await this.workspaceService.create(user, workspaceData, manager);
|
||||
return await this.workspaceService.create(user, workspaceData, trx);
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
|
||||
async initialSetup(
|
||||
createAdminUserDto: CreateAdminUserDto,
|
||||
manager?: EntityManager,
|
||||
): Promise<User> {
|
||||
return await transactionWrapper(
|
||||
async (manager: EntityManager) => {
|
||||
trx?: KyselyTransaction,
|
||||
) {
|
||||
return await executeTx(
|
||||
this.db,
|
||||
async (trx) => {
|
||||
// create user
|
||||
const user = await this.createUser(createAdminUserDto, manager);
|
||||
await this.createWorkspace(
|
||||
user,
|
||||
createAdminUserDto.workspaceName,
|
||||
manager,
|
||||
);
|
||||
const user = await this.userRepo.insertUser(createAdminUserDto, trx);
|
||||
await this.createWorkspace(user, createAdminUserDto.workspaceName, trx);
|
||||
return user;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// create user -
|
||||
// create workspace -
|
||||
// create default group
|
||||
// create space
|
||||
// add group to space instead of user
|
||||
|
||||
// add new users to default group
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { EnvironmentService } from '../../../integrations/environment/environment.service';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { TokensDto } from '../dto/tokens.dto';
|
||||
import { JwtPayload, JwtRefreshPayload, JwtType } from '../dto/jwt-payload';
|
||||
import { User } from '@docmost/db/types/entity.types';
|
||||
|
||||
@Injectable()
|
||||
export class TokenService {
|
||||
@ -32,7 +32,7 @@ export class TokenService {
|
||||
return this.jwtService.sign(payload, { expiresIn });
|
||||
}
|
||||
|
||||
async generateTokens(user: User): Promise<TokensDto> {
|
||||
async generateTokens(user): Promise<TokensDto> {
|
||||
return {
|
||||
accessToken: await this.generateAccessToken(user),
|
||||
refreshToken: await this.generateRefreshToken(user.id, user.workspaceId),
|
||||
|
||||
@ -7,18 +7,14 @@ import { PassportStrategy } from '@nestjs/passport';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { EnvironmentService } from '../../../integrations/environment/environment.service';
|
||||
import { JwtPayload, JwtType } from '../dto/jwt-payload';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { UserRepository } from '../../user/repositories/user.repository';
|
||||
import { UserService } from '../../user/user.service';
|
||||
import { WorkspaceRepository } from '../../workspace/repositories/workspace.repository';
|
||||
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||
import { UserRepo } from '@docmost/db/repos/user/user.repo';
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private userService: UserService,
|
||||
private userRepository: UserRepository,
|
||||
private workspaceRepository: WorkspaceRepository,
|
||||
private userRepo: UserRepo,
|
||||
private workspaceRepo: WorkspaceRepo,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
) {
|
||||
super({
|
||||
@ -29,7 +25,11 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
});
|
||||
}
|
||||
|
||||
async validate(req, payload: JwtPayload) {
|
||||
async validate(req: any, payload: JwtPayload) {
|
||||
if (!payload.workspaceId || payload.type !== JwtType.ACCESS) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
|
||||
// CLOUD ENV
|
||||
if (this.environmentService.isCloud()) {
|
||||
if (req.raw.workspaceId && req.raw.workspaceId !== payload.workspaceId) {
|
||||
@ -37,23 +37,12 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
}
|
||||
}
|
||||
|
||||
if (!payload.workspaceId || payload.type !== JwtType.ACCESS) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
|
||||
const workspace = await this.workspaceRepository.findById(
|
||||
payload.workspaceId,
|
||||
);
|
||||
const workspace = await this.workspaceRepo.findById(payload.workspaceId);
|
||||
|
||||
if (!workspace) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
const user = await this.userRepository.findOne({
|
||||
where: {
|
||||
id: payload.sub,
|
||||
workspaceId: payload.workspaceId,
|
||||
},
|
||||
});
|
||||
const user = await this.userRepo.findById(payload.sub, payload.workspaceId);
|
||||
|
||||
if (!user) {
|
||||
throw new UnauthorizedException();
|
||||
|
||||
Reference in New Issue
Block a user