mirror of
https://github.com/docmost/docmost.git
synced 2026-05-18 23:44:24 +08:00
@@ -3,6 +3,7 @@ import {
|
||||
Controller,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Inject,
|
||||
Post,
|
||||
Res,
|
||||
UseGuards,
|
||||
@@ -24,6 +25,11 @@ import { VerifyUserTokenDto } from './dto/verify-user-token.dto';
|
||||
import { FastifyReply } from 'fastify';
|
||||
import { validateSsoEnforcement } from './auth.util';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { AuditEvent, AuditResource } from '../../common/events/audit-events';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
IAuditService,
|
||||
} from '../../integrations/audit/audit.service';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
@@ -33,6 +39,7 @@ export class AuthController {
|
||||
private authService: AuthService,
|
||||
private environmentService: EnvironmentService,
|
||||
private moduleRef: ModuleRef,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@@ -169,8 +176,17 @@ export class AuthController {
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('logout')
|
||||
async logout(@Res({ passthrough: true }) res: FastifyReply) {
|
||||
async logout(
|
||||
@AuthUser() user: User,
|
||||
@Res({ passthrough: true }) res: FastifyReply,
|
||||
) {
|
||||
res.clearCookie('authToken');
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.USER_LOGOUT,
|
||||
resourceType: AuditResource.USER,
|
||||
resourceId: user.id,
|
||||
});
|
||||
}
|
||||
|
||||
setAuthCookie(res: FastifyReply, token: string) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Inject,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
UnauthorizedException,
|
||||
@@ -29,6 +30,11 @@ import { InjectKysely } from 'nestjs-kysely';
|
||||
import { executeTx } from '@docmost/db/utils';
|
||||
import { VerifyUserTokenDto } from '../dto/verify-user-token.dto';
|
||||
import { DomainService } from '../../../integrations/environment/domain.service';
|
||||
import { AuditEvent, AuditResource } from '../../../common/events/audit-events';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
IAuditService,
|
||||
} from '../../../integrations/audit/audit.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
@@ -40,6 +46,7 @@ export class AuthService {
|
||||
private mailService: MailService,
|
||||
private domainService: DomainService,
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
async login(loginDto: LoginDto, workspaceId: string) {
|
||||
@@ -64,6 +71,13 @@ export class AuthService {
|
||||
user.lastLoginAt = new Date();
|
||||
await this.userRepo.updateLastLogin(user.id, workspaceId);
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.USER_LOGIN,
|
||||
resourceType: AuditResource.USER,
|
||||
resourceId: user.id,
|
||||
metadata: { source: 'password' },
|
||||
});
|
||||
|
||||
return this.tokenService.generateAccessToken(user);
|
||||
}
|
||||
|
||||
@@ -112,6 +126,12 @@ export class AuthService {
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.USER_PASSWORD_CHANGED,
|
||||
resourceType: AuditResource.USER,
|
||||
resourceId: userId,
|
||||
});
|
||||
|
||||
const emailTemplate = ChangePasswordEmail({ username: user.name });
|
||||
await this.mailService.sendToQueue({
|
||||
to: user.email,
|
||||
@@ -135,16 +155,27 @@ export class AuthService {
|
||||
|
||||
const token = nanoIdGen(16);
|
||||
|
||||
const resetLink = `${this.domainService.getUrl(workspace.hostname)}/password-reset?token=${token}`;
|
||||
await executeTx(this.db, async (trx) => {
|
||||
await trx
|
||||
.deleteFrom('userTokens')
|
||||
.where('userId', '=', user.id)
|
||||
.where('type', '=', UserTokenType.FORGOT_PASSWORD)
|
||||
.execute();
|
||||
|
||||
await this.userTokenRepo.insertUserToken({
|
||||
token: token,
|
||||
userId: user.id,
|
||||
workspaceId: user.workspaceId,
|
||||
expiresAt: new Date(new Date().getTime() + 60 * 60 * 1000), // 1 hour
|
||||
type: UserTokenType.FORGOT_PASSWORD,
|
||||
await this.userTokenRepo.insertUserToken(
|
||||
{
|
||||
token,
|
||||
userId: user.id,
|
||||
workspaceId: user.workspaceId,
|
||||
expiresAt: new Date(Date.now() + 30 * 60 * 1000), // 30 minutes
|
||||
type: UserTokenType.FORGOT_PASSWORD,
|
||||
},
|
||||
{ trx },
|
||||
);
|
||||
});
|
||||
|
||||
const resetLink = `${this.domainService.getUrl(workspace.hostname)}/password-reset?token=${token}`;
|
||||
|
||||
const emailTemplate = ForgotPasswordEmail({
|
||||
username: user.name,
|
||||
resetLink: resetLink,
|
||||
@@ -201,6 +232,13 @@ export class AuthService {
|
||||
.execute();
|
||||
});
|
||||
|
||||
this.auditService.setActorId(user.id);
|
||||
this.auditService.log({
|
||||
event: AuditEvent.USER_PASSWORD_RESET,
|
||||
resourceType: AuditResource.USER,
|
||||
resourceId: user.id,
|
||||
});
|
||||
|
||||
const emailTemplate = ChangePasswordEmail({ username: user.name });
|
||||
await this.mailService.sendToQueue({
|
||||
to: user.email,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
|
||||
import { CreateUserDto } from '../dto/create-user.dto';
|
||||
import { WorkspaceService } from '../../workspace/services/workspace.service';
|
||||
import { CreateWorkspaceDto } from '../../workspace/dto/create-workspace.dto';
|
||||
@@ -10,6 +10,11 @@ import { InjectKysely } from 'nestjs-kysely';
|
||||
import { User, Workspace } from '@docmost/db/types/entity.types';
|
||||
import { GroupUserRepo } from '@docmost/db/repos/group/group-user.repo';
|
||||
import { UserRole } from '../../../common/helpers/types/permission';
|
||||
import { AuditEvent, AuditResource } from '../../../common/events/audit-events';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
IAuditService,
|
||||
} from '../../../integrations/audit/audit.service';
|
||||
|
||||
@Injectable()
|
||||
export class SignupService {
|
||||
@@ -18,6 +23,7 @@ export class SignupService {
|
||||
private workspaceService: WorkspaceService,
|
||||
private groupUserRepo: GroupUserRepo,
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
async signup(
|
||||
@@ -36,7 +42,7 @@ export class SignupService {
|
||||
);
|
||||
}
|
||||
|
||||
return await executeTx(
|
||||
const user = await executeTx(
|
||||
this.db,
|
||||
async (trx) => {
|
||||
// create user
|
||||
@@ -66,6 +72,24 @@ export class SignupService {
|
||||
},
|
||||
trx,
|
||||
);
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.USER_CREATED,
|
||||
resourceType: AuditResource.USER,
|
||||
resourceId: user.id,
|
||||
changes: {
|
||||
after: {
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
source: 'signup',
|
||||
},
|
||||
});
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
async initialSetup(
|
||||
|
||||
Reference in New Issue
Block a user