feat: logout sessions on password change (#23188)

* log out ohter sessions on password change

* translations

* update and add tests

* rename event to UserLogoutOtherSessions

* fix typo

* requested changes

* fix tests

* fix medium:test

* use ValidateBoolean

* fix format

* dont delete current session id

* Update server/src/dtos/auth.dto.ts

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>

* rename event and invalidateOtherSessions

* chore: cleanup

---------

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jason@rasm.me>
This commit is contained in:
Jorge Montejo
2025-10-27 14:16:10 +01:00
committed by GitHub
parent 6bb1a9e083
commit 382481735a
15 changed files with 90 additions and 19 deletions
+11 -9
View File
@@ -1,6 +1,6 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { DateTime } from 'luxon';
import { OnJob } from 'src/decorators';
import { OnEvent, OnJob } from 'src/decorators';
import { AuthDto } from 'src/dtos/auth.dto';
import {
SessionCreateDto,
@@ -10,6 +10,7 @@ import {
mapSession,
} from 'src/dtos/session.dto';
import { JobName, JobStatus, Permission, QueueName } from 'src/enum';
import { ArgOf } from 'src/repositories/event.repository';
import { BaseService } from 'src/services/base.service';
@Injectable()
@@ -69,18 +70,19 @@ export class SessionService extends BaseService {
await this.sessionRepository.delete(id);
}
async deleteAll(auth: AuthDto): Promise<void> {
const userId = auth.user.id;
const currentSessionId = auth.session?.id;
await this.sessionRepository.invalidate({ userId, excludeId: currentSessionId });
}
async lock(auth: AuthDto, id: string): Promise<void> {
await this.requireAccess({ auth, permission: Permission.SessionLock, ids: [id] });
await this.sessionRepository.update(id, { pinExpiresAt: null });
}
async deleteAll(auth: AuthDto): Promise<void> {
const sessions = await this.sessionRepository.getByUserId(auth.user.id);
for (const session of sessions) {
if (session.id === auth.session?.id) {
continue;
}
await this.sessionRepository.delete(session.id);
}
@OnEvent({ name: 'AuthChangePassword' })
async onAuthChangePassword({ userId, currentSessionId }: ArgOf<'AuthChangePassword'>): Promise<void> {
await this.sessionRepository.invalidate({ userId, excludeId: currentSessionId });
}
}