mirror of
https://github.com/standardnotes/server
synced 2026-07-14 09:01:33 -04:00
feat(auth): add session traces cleanup procedure
This commit is contained in:
@@ -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)
|
||||
})
|
||||
})
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user