feat(auth): add session traces cleanup procedure

This commit is contained in:
Karol Sójko
2022-12-19 12:49:59 +01:00
parent c12d354900
commit 147d8fd9af
10 changed files with 95 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
import 'reflect-metadata'
import 'newrelic'
import { Logger } from 'winston'
import { ContainerConfigLoader } from '../src/Bootstrap/Container'
import TYPES from '../src/Bootstrap/Types'
import { Env } from '../src/Bootstrap/Env'
import { CleanupSessionTraces } from '../src/Domain/UseCase/CleanupSessionTraces/CleanupSessionTraces'
const container = new ContainerConfigLoader()
void container.load().then((container) => {
const env: Env = new Env()
env.load()
const logger: Logger = container.get(TYPES.Logger)
logger.info('Starting session traces cleanup')
const cleanupSessionTraces: CleanupSessionTraces = container.get(TYPES.CleanupSessionTraces)
Promise.resolve(
cleanupSessionTraces.execute({
date: new Date(),
}),
)
.then(() => {
logger.info('Expired session traces cleaned.')
process.exit(0)
})
.catch((error) => {
logger.error(`Could not clean session traces: ${error.message}`)
process.exit(1)
})
})
+5
View File
@@ -19,6 +19,11 @@ case "$COMMAND" in
yarn workspace @standardnotes/auth-server worker
;;
'cleanup' )
echo "[Docker] Starting Cleanup..."
yarn workspace @standardnotes/auth-server cleanup
;;
'email-daily-backup' )
echo "[Docker] Starting Email Daily Backup..."
yarn workspace @standardnotes/auth-server daily-backup:email
+1
View File
@@ -19,6 +19,7 @@
"test": "jest --coverage --config=./jest.config.js --maxWorkers=50%",
"start": "yarn node dist/bin/server.js",
"worker": "yarn node dist/bin/worker.js",
"cleanup": "yarn node dist/bin/cleanup.js",
"daily-backup:email": "yarn node dist/bin/backup.js email daily",
"user-email-backup": "yarn node dist/bin/user_email_backup.js",
"daily-backup:dropbox": "yarn node dist/bin/backup.js dropbox daily",
+5
View File
@@ -201,6 +201,7 @@ import { SessionTracePersistenceMapper } from '../Mapping/SessionTracePersistenc
import { SessionTrace } from '../Domain/Session/SessionTrace'
import { TypeORMSessionTrace } from '../Infra/TypeORM/TypeORMSessionTrace'
import { TraceSession } from '../Domain/UseCase/TraceSession/TraceSession'
import { CleanupSessionTraces } from '../Domain/UseCase/CleanupSessionTraces/CleanupSessionTraces'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const newrelicFormatter = require('@newrelic/winston-enricher')
@@ -499,6 +500,10 @@ export class ContainerConfigLoader {
container.get(TYPES.SESSION_TRACE_DAYS_TTL),
),
)
container
.bind<CleanupSessionTraces>(TYPES.CleanupSessionTraces)
.toConstantValue(new CleanupSessionTraces(container.get(TYPES.SessionTraceRepository)))
container.bind<AuthenticateUser>(TYPES.AuthenticateUser).to(AuthenticateUser)
container.bind<AuthenticateRequest>(TYPES.AuthenticateRequest).to(AuthenticateRequest)
container.bind<RefreshSessionToken>(TYPES.RefreshSessionToken).to(RefreshSessionToken)
+1
View File
@@ -125,6 +125,7 @@ const TYPES = {
CreateCrossServiceToken: Symbol.for('CreateCrossServiceToken'),
ProcessUserRequest: Symbol.for('ProcessUserRequest'),
TraceSession: Symbol.for('TraceSession'),
CleanupSessionTraces: Symbol.for('CleanupSessionTraces'),
// Handlers
UserRegisteredEventHandler: Symbol.for('UserRegisteredEventHandler'),
AccountDeletionRequestedEventHandler: Symbol.for('AccountDeletionRequestedEventHandler'),
@@ -4,5 +4,6 @@ import { SessionTrace } from './SessionTrace'
export interface SessionTraceRepositoryInterface {
save(sessionTrace: SessionTrace): Promise<void>
removeExpiredBefore(date: Date): Promise<void>
findOneByUserUuidAndDate(userUuid: Uuid, date: Date): Promise<SessionTrace | null>
}
@@ -0,0 +1,19 @@
import { SessionTraceRepositoryInterface } from '../../Session/SessionTraceRepositoryInterface'
import { CleanupSessionTraces } from './CleanupSessionTraces'
describe('CleanupSessionTraces', () => {
let sessionTracesRepository: SessionTraceRepositoryInterface
const createUseCase = () => new CleanupSessionTraces(sessionTracesRepository)
beforeEach(() => {
sessionTracesRepository = {} as jest.Mocked<SessionTraceRepositoryInterface>
sessionTracesRepository.removeExpiredBefore = jest.fn()
})
it('should remove stale session traces', async () => {
await createUseCase().execute({ date: new Date() })
expect(sessionTracesRepository.removeExpiredBefore).toHaveBeenCalled()
})
})
@@ -0,0 +1,14 @@
import { Result, UseCaseInterface } from '@standardnotes/domain-core'
import { SessionTraceRepositoryInterface } from '../../Session/SessionTraceRepositoryInterface'
import { CleanupSessionTracesDTO } from './CleanupSessionTracesDTO'
export class CleanupSessionTraces implements UseCaseInterface<string> {
constructor(private sessionTracesRepository: SessionTraceRepositoryInterface) {}
async execute(dto: CleanupSessionTracesDTO): Promise<Result<string>> {
await this.sessionTracesRepository.removeExpiredBefore(dto.date)
return Result.ok('Session traces removed')
}
}
@@ -0,0 +1,3 @@
export interface CleanupSessionTracesDTO {
date: Date
}
@@ -10,6 +10,14 @@ export class MySQLSessionTraceRepository implements SessionTraceRepositoryInterf
private mapper: MapperInterface<SessionTrace, TypeORMSessionTrace>,
) {}
async removeExpiredBefore(date: Date): Promise<void> {
await this.ormRepository
.createQueryBuilder()
.delete()
.where('expires_at < :date', { date: date.toISOString() })
.execute()
}
async findOneByUserUuidAndDate(userUuid: Uuid, date: Date): Promise<SessionTrace | null> {
const typeOrm = await this.ormRepository
.createQueryBuilder('trace')