fix(session-service): properly handle session store results

Previously, an undefined result in fetchUsernameForSessionId
was handled the same way as an error, rejecting the promise.

This fixes the behavior, only rejecting the promise if an error
is returned from the session store and properly returning
undefined if the session store returns that.

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2023-10-07 18:30:42 +02:00
parent 4426d6f51a
commit 56e2270736
4 changed files with 27 additions and 6 deletions

View file

@ -128,10 +128,14 @@ export class WebsocketGateway implements OnGatewayConnection {
): Promise<User | null> { ): Promise<User | null> {
const sessionId = this.sessionService.extractSessionIdFromRequest(request); const sessionId = this.sessionService.extractSessionIdFromRequest(request);
this.logger.debug(
'Checking if sessionId is empty',
'findUserByRequestSession',
);
if (sessionId.isEmpty()) { if (sessionId.isEmpty()) {
return null; return null;
} }
this.logger.debug('sessionId is not empty', 'findUserByRequestSession');
const username = await this.sessionService.fetchUsernameForSessionId( const username = await this.sessionService.fetchUsernameForSessionId(
sessionId.get(), sessionId.get(),
); );

View file

@ -6,11 +6,12 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { LoggerModule } from '../logger/logger.module';
import { Session } from './session.entity'; import { Session } from './session.entity';
import { SessionService } from './session.service'; import { SessionService } from './session.service';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([Session])], imports: [TypeOrmModule.forFeature([Session]), LoggerModule],
exports: [SessionService], exports: [SessionService],
providers: [SessionService], providers: [SessionService],
}) })

View file

@ -11,9 +11,12 @@ import { IncomingMessage } from 'http';
import { Mock } from 'ts-mockery'; import { Mock } from 'ts-mockery';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { AppConfig } from '../config/app.config';
import { AuthConfig } from '../config/auth.config'; import { AuthConfig } from '../config/auth.config';
import { DatabaseType } from '../config/database-type.enum'; import { DatabaseType } from '../config/database-type.enum';
import { DatabaseConfig } from '../config/database.config'; import { DatabaseConfig } from '../config/database.config';
import { Loglevel } from '../config/loglevel.enum';
import { ConsoleLoggerService } from '../logger/console-logger.service';
import { HEDGEDOC_SESSION } from '../utils/session'; import { HEDGEDOC_SESSION } from '../utils/session';
import { Session } from './session.entity'; import { Session } from './session.entity';
import { SessionService, SessionState } from './session.service'; import { SessionService, SessionState } from './session.service';
@ -63,6 +66,7 @@ describe('SessionService', () => {
.mockReturnValue(mockedTypeormStore); .mockReturnValue(mockedTypeormStore);
sessionService = new SessionService( sessionService = new SessionService(
new ConsoleLoggerService({ loglevel: Loglevel.DEBUG } as AppConfig),
mockedSessionRepository, mockedSessionRepository,
databaseConfigMock, databaseConfigMock,
authConfigMock, authConfigMock,

View file

@ -17,6 +17,7 @@ import { DatabaseType } from '../config/database-type.enum';
import databaseConfiguration, { import databaseConfiguration, {
DatabaseConfig, DatabaseConfig,
} from '../config/database.config'; } from '../config/database.config';
import { ConsoleLoggerService } from '../logger/console-logger.service';
import { HEDGEDOC_SESSION } from '../utils/session'; import { HEDGEDOC_SESSION } from '../utils/session';
import { Username } from '../utils/username'; import { Username } from '../utils/username';
import { Session } from './session.entity'; import { Session } from './session.entity';
@ -36,12 +37,14 @@ export class SessionService {
private readonly typeormStore: TypeormStore; private readonly typeormStore: TypeormStore;
constructor( constructor(
private readonly logger: ConsoleLoggerService,
@InjectRepository(Session) private sessionRepository: Repository<Session>, @InjectRepository(Session) private sessionRepository: Repository<Session>,
@Inject(databaseConfiguration.KEY) @Inject(databaseConfiguration.KEY)
private dbConfig: DatabaseConfig, private dbConfig: DatabaseConfig,
@Inject(authConfiguration.KEY) @Inject(authConfiguration.KEY)
private authConfig: AuthConfig, private authConfig: AuthConfig,
) { ) {
this.logger.setContext(SessionService.name);
this.typeormStore = new TypeormStore({ this.typeormStore = new TypeormStore({
cleanupLimit: 2, cleanupLimit: 2,
limitSubquery: dbConfig.type !== DatabaseType.MARIADB, limitSubquery: dbConfig.type !== DatabaseType.MARIADB,
@ -61,12 +64,21 @@ export class SessionService {
*/ */
fetchUsernameForSessionId(sessionId: string): Promise<Username | undefined> { fetchUsernameForSessionId(sessionId: string): Promise<Username | undefined> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.logger.debug(
`Fetching username for sessionId ${sessionId}`,
'fetchUsernameForSessionId',
);
this.typeormStore.get( this.typeormStore.get(
sessionId, sessionId,
(error?: Error, result?: SessionState) => (error?: Error, result?: SessionState) => {
error || !result this.logger.debug(
? reject(error) // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
: resolve(result.username as Username), `Got error ${error}, result ${result?.username} for sessionId ${sessionId}`,
'fetchUsernameForSessionId',
);
if (error) return reject(error);
return resolve(result?.username as Username);
},
); );
}); });
} }