feat(auth): add sqlite driver repositories (#580)

* feat(auth): add pkce sqlite repository for home server

* feat(auth): add sqlite subscription token repository for home server
This commit is contained in:
Karol Sójko 2023-05-01 14:50:36 +02:00 committed by GitHub
parent c108bfb12f
commit 97124928df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 4 deletions

View file

@ -226,6 +226,8 @@ import { TypeORMLockRepository } from '../Infra/TypeORM/TypeORMLockRepository'
import { EphemeralSessionRepositoryInterface } from '../Domain/Session/EphemeralSessionRepositoryInterface'
import { TypeORMEphemeralSessionRepository } from '../Infra/TypeORM/TypeORMEphemeralSessionRepository'
import { TypeORMOfflineSubscriptionTokenRepository } from '../Infra/TypeORM/TypeORMOfflineSubscriptionTokenRepository'
import { TypeORMPKCERepository } from '../Infra/TypeORM/TypeORMPKCERepository'
import { TypeORMSubscriptionTokenRepository } from '../Infra/TypeORM/TypeORMSubscriptionTokenRepository'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const newrelicFormatter = require('@newrelic/winston-enricher')
@ -374,13 +376,9 @@ export class ContainerConfigLoader {
container
.bind<OfflineUserSubscriptionRepositoryInterface>(TYPES.OfflineUserSubscriptionRepository)
.to(TypeORMOfflineUserSubscriptionRepository)
container
.bind<SubscriptionTokenRepositoryInterface>(TYPES.SubscriptionTokenRepository)
.to(RedisSubscriptionTokenRepository)
container
.bind<SharedSubscriptionInvitationRepositoryInterface>(TYPES.SharedSubscriptionInvitationRepository)
.to(TypeORMSharedSubscriptionInvitationRepository)
container.bind<PKCERepositoryInterface>(TYPES.PKCERepository).to(RedisPKCERepository)
container
.bind<SessionTraceRepositoryInterface>(TYPES.SessionTraceRepository)
.toConstantValue(
@ -518,7 +516,22 @@ export class ContainerConfigLoader {
container.get(TYPES.Timer),
),
)
container
.bind<PKCERepositoryInterface>(TYPES.PKCERepository)
.toConstantValue(
new TypeORMPKCERepository(
container.get(TYPES.CacheEntryRepository),
container.get(TYPES.Logger),
container.get(TYPES.Timer),
),
)
container
.bind<SubscriptionTokenRepositoryInterface>(TYPES.SubscriptionTokenRepository)
.toConstantValue(
new TypeORMSubscriptionTokenRepository(container.get(TYPES.CacheEntryRepository), container.get(TYPES.Timer)),
)
} else {
container.bind<PKCERepositoryInterface>(TYPES.PKCERepository).to(RedisPKCERepository)
container.bind<LockRepositoryInterface>(TYPES.LockRepository).to(LockRepository)
container
.bind<EphemeralSessionRepositoryInterface>(TYPES.EphemeralSessionRepository)
@ -526,6 +539,9 @@ export class ContainerConfigLoader {
container
.bind<OfflineSubscriptionTokenRepositoryInterface>(TYPES.OfflineSubscriptionTokenRepository)
.to(RedisOfflineSubscriptionTokenRepository)
container
.bind<SubscriptionTokenRepositoryInterface>(TYPES.SubscriptionTokenRepository)
.to(RedisSubscriptionTokenRepository)
}
// Services

View file

@ -0,0 +1,34 @@
import { TimerInterface } from '@standardnotes/time'
import { Logger } from 'winston'
import { CacheEntry } from '../../Domain/Cache/CacheEntry'
import { CacheEntryRepositoryInterface } from '../../Domain/Cache/CacheEntryRepositoryInterface'
import { PKCERepositoryInterface } from '../../Domain/User/PKCERepositoryInterface'
export class TypeORMPKCERepository implements PKCERepositoryInterface {
private readonly PREFIX = 'pkce'
constructor(
private cacheEntryRepository: CacheEntryRepositoryInterface,
private logger: Logger,
private timer: TimerInterface,
) {}
async storeCodeChallenge(codeChallenge: string): Promise<void> {
this.logger.debug(`Storing code challenge: ${codeChallenge}`)
await this.cacheEntryRepository.save(
CacheEntry.create({
key: `${this.PREFIX}:${codeChallenge}`,
value: codeChallenge,
expiresAt: this.timer.getUTCDateNSecondsAhead(3600),
}).getValue(),
)
}
async removeCodeChallenge(codeChallenge: string): Promise<boolean> {
await this.cacheEntryRepository.removeByKey(`${this.PREFIX}:${codeChallenge}`)
return true
}
}

View file

@ -0,0 +1,34 @@
import { SubscriptionToken } from '../../Domain/Subscription/SubscriptionToken'
import { SubscriptionTokenRepositoryInterface } from '../../Domain/Subscription/SubscriptionTokenRepositoryInterface'
import { TimerInterface } from '@standardnotes/time'
import { CacheEntryRepositoryInterface } from '../../Domain/Cache/CacheEntryRepositoryInterface'
import { CacheEntry } from '../../Domain/Cache/CacheEntry'
export class TypeORMSubscriptionTokenRepository implements SubscriptionTokenRepositoryInterface {
private readonly PREFIX = 'subscription-token'
constructor(private cacheEntryRepository: CacheEntryRepositoryInterface, private timer: TimerInterface) {}
async getUserUuidByToken(token: string): Promise<string | undefined> {
const userUuid = await this.cacheEntryRepository.findUnexpiredOneByKey(`${this.PREFIX}:${token}`)
if (!userUuid) {
return undefined
}
return userUuid.props.value
}
async save(subscriptionToken: SubscriptionToken): Promise<boolean> {
const key = `${this.PREFIX}:${subscriptionToken.token}`
await this.cacheEntryRepository.save(
CacheEntry.create({
key,
value: subscriptionToken.userUuid,
expiresAt: this.timer.convertMicrosecondsToDate(subscriptionToken.expiresAt),
}).getValue(),
)
return true
}
}