fix(auth): subscription token ttl

This commit is contained in:
Karol Sójko
2022-09-22 16:24:33 +02:00
parent 81eb4be200
commit 6efd336f34
5 changed files with 14 additions and 38 deletions
@@ -1,5 +1,5 @@
export type SubscriptionToken = {
userUuid: string
token: string
expiresAt: number
ttl: number
}
@@ -1,7 +1,6 @@
import 'reflect-metadata'
import { CryptoNode } from '@standardnotes/sncrypto-node'
import { TimerInterface } from '@standardnotes/time'
import { SubscriptionTokenRepositoryInterface } from '../../Subscription/SubscriptionTokenRepositoryInterface'
import { CreateSubscriptionToken } from './CreateSubscriptionToken'
@@ -10,10 +9,9 @@ import { Logger } from 'winston'
describe('CreateSubscriptionToken', () => {
let subscriptionTokenRepository: SubscriptionTokenRepositoryInterface
let cryptoNode: CryptoNode
let timer: TimerInterface
let logger: Logger
const createUseCase = () => new CreateSubscriptionToken(subscriptionTokenRepository, cryptoNode, timer, logger)
const createUseCase = () => new CreateSubscriptionToken(subscriptionTokenRepository, cryptoNode, logger)
beforeEach(() => {
subscriptionTokenRepository = {} as jest.Mocked<SubscriptionTokenRepositoryInterface>
@@ -22,10 +20,6 @@ describe('CreateSubscriptionToken', () => {
cryptoNode = {} as jest.Mocked<CryptoNode>
cryptoNode.generateRandomKey = jest.fn().mockReturnValueOnce('random-string')
timer = {} as jest.Mocked<TimerInterface>
timer.convertStringDateToMicroseconds = jest.fn().mockReturnValue(1)
timer.getUTCDateNHoursAhead = jest.fn().mockReturnValue(new Date(1))
logger = {} as jest.Mocked<Logger>
logger.error = jest.fn()
})
@@ -38,7 +32,7 @@ describe('CreateSubscriptionToken', () => {
expect(subscriptionTokenRepository.save).toHaveBeenCalledWith({
userUuid: '1-2-3',
token: 'random-string',
expiresAt: 1,
ttl: 10_800,
})
})
@@ -1,5 +1,4 @@
import { CryptoNode } from '@standardnotes/sncrypto-node'
import { TimerInterface } from '@standardnotes/time'
import { inject, injectable } from 'inversify'
import { Logger } from 'winston'
@@ -15,7 +14,6 @@ export class CreateSubscriptionToken implements UseCaseInterface {
@inject(TYPES.SubscriptionTokenRepository)
private subscriptionTokenRepository: SubscriptionTokenRepositoryInterface,
@inject(TYPES.CryptoNode) private cryptoNode: CryptoNode,
@inject(TYPES.Timer) private timer: TimerInterface,
@inject(TYPES.Logger) private logger: Logger,
) {}
@@ -25,7 +23,7 @@ export class CreateSubscriptionToken implements UseCaseInterface {
const subscriptionToken = {
userUuid: dto.userUuid,
token,
expiresAt: this.timer.convertStringDateToMicroseconds(this.timer.getUTCDateNHoursAhead(3).toString()),
ttl: 10_800,
}
const subscriptionTokenWasSaved = await this.subscriptionTokenRepository.save(subscriptionToken)
@@ -1,25 +1,19 @@
import 'reflect-metadata'
import * as IORedis from 'ioredis'
import { TimerInterface } from '@standardnotes/time'
import { RedisSubscriptionTokenRepository } from './RedisSubscriptionTokenRepository'
import { SubscriptionToken } from '../../Domain/Subscription/SubscriptionToken'
describe('RedisSubscriptionTokenRepository', () => {
let redisClient: IORedis.Redis
let timer: TimerInterface
const createRepository = () => new RedisSubscriptionTokenRepository(redisClient, timer)
const createRepository = () => new RedisSubscriptionTokenRepository(redisClient)
beforeEach(() => {
redisClient = {} as jest.Mocked<IORedis.Redis>
redisClient.set = jest.fn().mockReturnValue('OK')
redisClient.setex = jest.fn().mockReturnValue('OK')
redisClient.get = jest.fn()
redisClient.expireat = jest.fn().mockReturnValue(1)
timer = {} as jest.Mocked<TimerInterface>
timer.convertMicrosecondsToSeconds = jest.fn().mockReturnValue(1)
})
it('should get a user uuid in exchange for an subscription token', async () => {
@@ -42,29 +36,25 @@ describe('RedisSubscriptionTokenRepository', () => {
const subscriptionToken: SubscriptionToken = {
userUuid: '1-2-3',
token: 'random-string',
expiresAt: 123,
ttl: 123,
}
expect(await createRepository().save(subscriptionToken)).toBeTruthy()
expect(redisClient.set).toHaveBeenCalledWith('subscription-token:random-string', '1-2-3')
expect(redisClient.expireat).toHaveBeenCalledWith('subscription-token:random-string', 1)
expect(redisClient.setex).toHaveBeenCalledWith('subscription-token:random-string', 123, '1-2-3')
})
it('should indicate subscription token was not saved', async () => {
redisClient.set = jest.fn().mockReturnValue(null)
redisClient.setex = jest.fn().mockReturnValue(null)
const subscriptionToken: SubscriptionToken = {
userUuid: '1-2-3',
token: 'random-string',
expiresAt: 123,
ttl: 123,
}
expect(await createRepository().save(subscriptionToken)).toBeFalsy()
expect(redisClient.set).toHaveBeenCalledWith('subscription-token:random-string', '1-2-3')
expect(redisClient.expireat).toHaveBeenCalledWith('subscription-token:random-string', 1)
expect(redisClient.setex).toHaveBeenCalledWith('subscription-token:random-string', 123, '1-2-3')
})
})
@@ -4,16 +4,12 @@ import { inject, injectable } from 'inversify'
import TYPES from '../../Bootstrap/Types'
import { SubscriptionToken } from '../../Domain/Subscription/SubscriptionToken'
import { SubscriptionTokenRepositoryInterface } from '../../Domain/Subscription/SubscriptionTokenRepositoryInterface'
import { TimerInterface } from '@standardnotes/time'
@injectable()
export class RedisSubscriptionTokenRepository implements SubscriptionTokenRepositoryInterface {
private readonly PREFIX = 'subscription-token'
constructor(
@inject(TYPES.Redis) private redisClient: IORedis.Redis,
@inject(TYPES.Timer) private timer: TimerInterface,
) {}
constructor(@inject(TYPES.Redis) private redisClient: IORedis.Redis) {}
async getUserUuidByToken(token: string): Promise<string | undefined> {
const userUuid = await this.redisClient.get(`${this.PREFIX}:${token}`)
@@ -26,11 +22,9 @@ export class RedisSubscriptionTokenRepository implements SubscriptionTokenReposi
async save(subscriptionToken: SubscriptionToken): Promise<boolean> {
const key = `${this.PREFIX}:${subscriptionToken.token}`
const expiresAtTimestampInSeconds = this.timer.convertMicrosecondsToSeconds(subscriptionToken.expiresAt)
const wasSet = await this.redisClient.set(key, subscriptionToken.userUuid)
const timeoutWasSet = await this.redisClient.expireat(key, expiresAtTimestampInSeconds)
const wasSet = await this.redisClient.setex(key, subscriptionToken.ttl, subscriptionToken.userUuid)
return wasSet === 'OK' && timeoutWasSet !== 0
return wasSet === 'OK'
}
}