mirror of
https://github.com/standardnotes/server
synced 2026-01-16 20:04:32 -05:00
fix(auth): reduce session select queries in favor of insert/update model
This commit is contained in:
@@ -5,5 +5,6 @@ export interface EphemeralSessionRepositoryInterface {
|
||||
findOneByUuidAndUserUuid(uuid: string, userUuid: string): Promise<EphemeralSession | null>
|
||||
findAllByUserUuid(userUuid: string): Promise<Array<EphemeralSession>>
|
||||
deleteOne(uuid: string, userUuid: string): Promise<void>
|
||||
save(ephemeralSession: EphemeralSession): Promise<void>
|
||||
insert(ephemeralSession: EphemeralSession): Promise<void>
|
||||
update(ephemeralSession: EphemeralSession): Promise<void>
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ import { RevokedSession } from './RevokedSession'
|
||||
export interface RevokedSessionRepositoryInterface {
|
||||
findOneByUuid(uuid: string): Promise<RevokedSession | null>
|
||||
findAllByUserUuid(userUuid: string): Promise<Array<RevokedSession>>
|
||||
save(revokedSession: RevokedSession): Promise<RevokedSession>
|
||||
insert(revokedSession: RevokedSession): Promise<void>
|
||||
update(revokedSession: RevokedSession): Promise<void>
|
||||
remove(revokedSession: RevokedSession): Promise<RevokedSession>
|
||||
clearUserAgentByUserUuid(userUuid: string): Promise<void>
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ export interface SessionRepositoryInterface {
|
||||
findAllByUserUuid(userUuid: string): Promise<Array<Session>>
|
||||
deleteAllByUserUuidExceptOne(dto: { userUuid: Uuid; currentSessionUuid: Uuid }): Promise<void>
|
||||
deleteOneByUuid(uuid: string): Promise<void>
|
||||
save(session: Session): Promise<Session>
|
||||
insert(session: Session): Promise<void>
|
||||
update(session: Session): Promise<void>
|
||||
remove(session: Session): Promise<Session>
|
||||
clearUserAgentByUserUuid(userUuid: string): Promise<void>
|
||||
removeExpiredBefore(date: Date): Promise<void>
|
||||
|
||||
@@ -69,18 +69,21 @@ describe('SessionService', () => {
|
||||
sessionRepository = {} as jest.Mocked<SessionRepositoryInterface>
|
||||
sessionRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
||||
sessionRepository.deleteOneByUuid = jest.fn()
|
||||
sessionRepository.save = jest.fn().mockReturnValue(existingSession)
|
||||
sessionRepository.insert = jest.fn()
|
||||
sessionRepository.update = jest.fn()
|
||||
|
||||
settingService = {} as jest.Mocked<SettingServiceInterface>
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
|
||||
|
||||
ephemeralSessionRepository = {} as jest.Mocked<EphemeralSessionRepositoryInterface>
|
||||
ephemeralSessionRepository.save = jest.fn()
|
||||
ephemeralSessionRepository.insert = jest.fn()
|
||||
ephemeralSessionRepository.update = jest.fn()
|
||||
ephemeralSessionRepository.findOneByUuid = jest.fn()
|
||||
ephemeralSessionRepository.deleteOne = jest.fn()
|
||||
|
||||
revokedSessionRepository = {} as jest.Mocked<RevokedSessionRepositoryInterface>
|
||||
revokedSessionRepository.save = jest.fn()
|
||||
revokedSessionRepository.insert = jest.fn()
|
||||
revokedSessionRepository.update = jest.fn()
|
||||
|
||||
existingEphemeralSession = {} as jest.Mocked<EphemeralSession>
|
||||
existingEphemeralSession.uuid = '2-3-4'
|
||||
@@ -129,7 +132,7 @@ describe('SessionService', () => {
|
||||
it('should mark a revoked session as received', async () => {
|
||||
await createService().markRevokedSessionAsReceived(revokedSession)
|
||||
|
||||
expect(revokedSessionRepository.save).toHaveBeenCalledWith({
|
||||
expect(revokedSessionRepository.update).toHaveBeenCalledWith({
|
||||
uuid: '2e1e43',
|
||||
received: true,
|
||||
receivedAt: new Date(1),
|
||||
@@ -145,8 +148,8 @@ describe('SessionService', () => {
|
||||
readonly_access: false,
|
||||
})
|
||||
|
||||
expect(sessionRepository.save).toHaveBeenCalled()
|
||||
expect(ephemeralSessionRepository.save).not.toHaveBeenCalled()
|
||||
expect(sessionRepository.update).toHaveBeenCalled()
|
||||
expect(ephemeralSessionRepository.update).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should refresh access and refresh tokens for an ephemeral session', async () => {
|
||||
@@ -158,8 +161,8 @@ describe('SessionService', () => {
|
||||
readonly_access: false,
|
||||
})
|
||||
|
||||
expect(sessionRepository.save).not.toHaveBeenCalled()
|
||||
expect(ephemeralSessionRepository.save).toHaveBeenCalled()
|
||||
expect(sessionRepository.update).not.toHaveBeenCalled()
|
||||
expect(ephemeralSessionRepository.update).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should create new session for a user', async () => {
|
||||
@@ -173,8 +176,8 @@ describe('SessionService', () => {
|
||||
readonlyAccess: false,
|
||||
})
|
||||
|
||||
expect(sessionRepository.save).toHaveBeenCalledWith(expect.any(Session))
|
||||
expect(sessionRepository.save).toHaveBeenCalledWith({
|
||||
expect(sessionRepository.insert).toHaveBeenCalledWith(expect.any(Session))
|
||||
expect(sessionRepository.insert).toHaveBeenCalledWith({
|
||||
accessExpiration: expect.any(Date),
|
||||
apiVersion: '003',
|
||||
createdAt: expect.any(Date),
|
||||
@@ -209,8 +212,8 @@ describe('SessionService', () => {
|
||||
readonlyAccess: false,
|
||||
})
|
||||
|
||||
expect(sessionRepository.save).toHaveBeenCalledWith(expect.any(Session))
|
||||
expect(sessionRepository.save).toHaveBeenCalledWith({
|
||||
expect(sessionRepository.insert).toHaveBeenCalledWith(expect.any(Session))
|
||||
expect(sessionRepository.insert).toHaveBeenCalledWith({
|
||||
accessExpiration: expect.any(Date),
|
||||
apiVersion: '003',
|
||||
createdAt: expect.any(Date),
|
||||
@@ -248,8 +251,8 @@ describe('SessionService', () => {
|
||||
readonlyAccess: false,
|
||||
})
|
||||
|
||||
expect(sessionRepository.save).toHaveBeenCalledWith(expect.any(Session))
|
||||
expect(sessionRepository.save).toHaveBeenCalledWith({
|
||||
expect(sessionRepository.insert).toHaveBeenCalledWith(expect.any(Session))
|
||||
expect(sessionRepository.insert).toHaveBeenCalledWith({
|
||||
accessExpiration: expect.any(Date),
|
||||
apiVersion: '003',
|
||||
createdAt: expect.any(Date),
|
||||
@@ -405,8 +408,8 @@ describe('SessionService', () => {
|
||||
readonlyAccess: false,
|
||||
})
|
||||
|
||||
expect(ephemeralSessionRepository.save).toHaveBeenCalledWith(expect.any(EphemeralSession))
|
||||
expect(ephemeralSessionRepository.save).toHaveBeenCalledWith({
|
||||
expect(ephemeralSessionRepository.insert).toHaveBeenCalledWith(expect.any(EphemeralSession))
|
||||
expect(ephemeralSessionRepository.insert).toHaveBeenCalledWith({
|
||||
accessExpiration: expect.any(Date),
|
||||
apiVersion: '003',
|
||||
createdAt: expect.any(Date),
|
||||
@@ -684,7 +687,7 @@ describe('SessionService', () => {
|
||||
it('should revoked a session', async () => {
|
||||
await createService().createRevokedSession(existingSession)
|
||||
|
||||
expect(revokedSessionRepository.save).toHaveBeenCalledWith({
|
||||
expect(revokedSessionRepository.insert).toHaveBeenCalledWith({
|
||||
uuid: '2e1e43',
|
||||
userUuid: '1-2-3',
|
||||
userAgent: 'Chrome',
|
||||
|
||||
@@ -57,7 +57,7 @@ export class SessionService implements SessionServiceInterface {
|
||||
|
||||
const sessionPayload = await this.createTokens(session)
|
||||
|
||||
await this.sessionRepository.save(session)
|
||||
await this.sessionRepository.insert(session)
|
||||
|
||||
try {
|
||||
const userSubscription = await this.userSubscriptionRepository.findOneByUserUuid(dto.user.uuid)
|
||||
@@ -92,7 +92,7 @@ export class SessionService implements SessionServiceInterface {
|
||||
|
||||
const sessionPayload = await this.createTokens(ephemeralSession)
|
||||
|
||||
await this.ephemeralSessionRepository.save(ephemeralSession)
|
||||
await this.ephemeralSessionRepository.insert(ephemeralSession)
|
||||
|
||||
return {
|
||||
sessionHttpRepresentation: sessionPayload,
|
||||
@@ -104,9 +104,9 @@ export class SessionService implements SessionServiceInterface {
|
||||
const sessionPayload = await this.createTokens(dto.session)
|
||||
|
||||
if (dto.isEphemeral) {
|
||||
await this.ephemeralSessionRepository.save(dto.session)
|
||||
await this.ephemeralSessionRepository.update(dto.session)
|
||||
} else {
|
||||
await this.sessionRepository.save(dto.session)
|
||||
await this.sessionRepository.update(dto.session)
|
||||
}
|
||||
|
||||
return sessionPayload
|
||||
@@ -221,7 +221,9 @@ export class SessionService implements SessionServiceInterface {
|
||||
revokedSession.received = true
|
||||
revokedSession.receivedAt = this.timer.getUTCDate()
|
||||
|
||||
return this.revokedSessionRepository.save(revokedSession)
|
||||
await this.revokedSessionRepository.update(revokedSession)
|
||||
|
||||
return revokedSession
|
||||
}
|
||||
|
||||
async deleteSessionByToken(token: string): Promise<string | null> {
|
||||
@@ -248,7 +250,9 @@ export class SessionService implements SessionServiceInterface {
|
||||
revokedSession.apiVersion = session.apiVersion
|
||||
revokedSession.userAgent = session.userAgent
|
||||
|
||||
return this.revokedSessionRepository.save(revokedSession)
|
||||
await this.revokedSessionRepository.insert(revokedSession)
|
||||
|
||||
return revokedSession
|
||||
}
|
||||
|
||||
private async createSession(dto: {
|
||||
|
||||
@@ -42,7 +42,7 @@ export class RedisEphemeralSessionRepository implements EphemeralSessionReposito
|
||||
session.accessExpiration = accessExpiration
|
||||
session.refreshExpiration = refreshExpiration
|
||||
|
||||
await this.save(session)
|
||||
await this.update(session)
|
||||
}
|
||||
|
||||
async findAllByUserUuid(userUuid: string): Promise<Array<EphemeralSession>> {
|
||||
@@ -77,7 +77,7 @@ export class RedisEphemeralSessionRepository implements EphemeralSessionReposito
|
||||
return JSON.parse(stringifiedSession)
|
||||
}
|
||||
|
||||
async save(ephemeralSession: EphemeralSession): Promise<void> {
|
||||
async insert(ephemeralSession: EphemeralSession): Promise<void> {
|
||||
const ttl = this.ephemeralSessionAge
|
||||
|
||||
const stringifiedSession = JSON.stringify(ephemeralSession)
|
||||
@@ -92,4 +92,8 @@ export class RedisEphemeralSessionRepository implements EphemeralSessionReposito
|
||||
|
||||
await pipeline.exec()
|
||||
}
|
||||
|
||||
async update(ephemeralSession: EphemeralSession): Promise<void> {
|
||||
return this.insert(ephemeralSession)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,11 @@ export class TypeORMEphemeralSessionRepository implements EphemeralSessionReposi
|
||||
return JSON.parse(stringifiedSession.props.value)
|
||||
}
|
||||
|
||||
async save(ephemeralSession: EphemeralSession): Promise<void> {
|
||||
async update(ephemeralSession: EphemeralSession): Promise<void> {
|
||||
return this.insert(ephemeralSession)
|
||||
}
|
||||
|
||||
async insert(ephemeralSession: EphemeralSession): Promise<void> {
|
||||
const ttl = this.ephemeralSessionAge
|
||||
|
||||
ephemeralSession.updatedAt = this.timer.getUTCDate()
|
||||
|
||||
@@ -12,8 +12,14 @@ export class TypeORMRevokedSessionRepository implements RevokedSessionRepository
|
||||
private ormRepository: Repository<RevokedSession>,
|
||||
) {}
|
||||
|
||||
async save(revokedSession: RevokedSession): Promise<RevokedSession> {
|
||||
return this.ormRepository.save(revokedSession)
|
||||
async insert(revokedSession: RevokedSession): Promise<void> {
|
||||
await this.ormRepository.insert(revokedSession)
|
||||
}
|
||||
|
||||
async update(revokedSession: RevokedSession): Promise<void> {
|
||||
const { uuid, ...revokedSessionProps } = revokedSession
|
||||
|
||||
await this.ormRepository.update({ uuid }, revokedSessionProps)
|
||||
}
|
||||
|
||||
async remove(revokedSession: RevokedSession): Promise<RevokedSession> {
|
||||
|
||||
@@ -17,10 +17,18 @@ export class TypeORMSessionRepository implements SessionRepositoryInterface {
|
||||
@inject(TYPES.Auth_Timer) private timer: TimerInterface,
|
||||
) {}
|
||||
|
||||
async save(session: Session): Promise<Session> {
|
||||
async insert(session: Session): Promise<void> {
|
||||
session.updatedAt = this.timer.getUTCDate()
|
||||
|
||||
return this.ormRepository.save(session)
|
||||
await this.ormRepository.insert(session)
|
||||
}
|
||||
|
||||
async update(session: Session): Promise<void> {
|
||||
session.updatedAt = this.timer.getUTCDate()
|
||||
|
||||
const { uuid, ...sessionProps } = session
|
||||
|
||||
await this.ormRepository.update({ uuid }, sessionProps)
|
||||
}
|
||||
|
||||
async remove(session: Session): Promise<Session> {
|
||||
|
||||
Reference in New Issue
Block a user