fix(tbank): isolate caches by connection generation
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { BrokerageAccountDto } from './brokerage-account.dto';
|
||||
import {
|
||||
@@ -12,8 +13,12 @@ import {
|
||||
import { TbankClient, TbankAccount } from './tbank.client';
|
||||
import { TbankTokenService } from './tbank-token.service';
|
||||
|
||||
export type TbankAccountContext = {
|
||||
export type TbankConnectionContext = {
|
||||
token: string;
|
||||
generation: string;
|
||||
};
|
||||
|
||||
export type TbankAccountContext = TbankConnectionContext & {
|
||||
account: TbankAccount;
|
||||
};
|
||||
|
||||
@@ -33,13 +38,14 @@ export class TbankAccessService {
|
||||
userId: string,
|
||||
handler: (context: {
|
||||
token: string;
|
||||
generation: string;
|
||||
accounts: BrokerageAccountDto[];
|
||||
}) => Promise<T> | T,
|
||||
): Promise<T> {
|
||||
const { token } = await this.connection(userId);
|
||||
return this.tokens.translateInvalidToken(async () =>
|
||||
return this.withConnection(userId, async ({ token, generation }) =>
|
||||
handler({
|
||||
token,
|
||||
generation,
|
||||
accounts: supportedTbankAccounts(
|
||||
await this.tbank.getOpenAccounts(token),
|
||||
),
|
||||
@@ -47,28 +53,53 @@ export class TbankAccessService {
|
||||
);
|
||||
}
|
||||
|
||||
async withConnection<T>(
|
||||
userId: string,
|
||||
handler: (context: TbankConnectionContext) => Promise<T> | T,
|
||||
): Promise<T> {
|
||||
const connection = await this.connection(userId);
|
||||
return this.tokens.translateInvalidToken(async () => handler(connection));
|
||||
}
|
||||
|
||||
async withAccount<T>(
|
||||
userId: string,
|
||||
accountId: string,
|
||||
handler: (context: TbankAccountContext) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const { token } = await this.connection(userId);
|
||||
return this.withConnection(userId, (connection) =>
|
||||
this.withAccountForConnection(connection, accountId, handler),
|
||||
);
|
||||
}
|
||||
|
||||
async withAccountForConnection<T>(
|
||||
connection: TbankConnectionContext,
|
||||
accountId: string,
|
||||
handler: (context: TbankAccountContext) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const { token, generation } = connection;
|
||||
return this.tokens.translateInvalidToken(async () => {
|
||||
const account = accessibleTbankAccount(
|
||||
await this.tbank.getOpenAccounts(token),
|
||||
accountId,
|
||||
);
|
||||
if (!account) throw new NotFoundException();
|
||||
return handler({ token, account });
|
||||
return handler({ token, generation, account });
|
||||
});
|
||||
}
|
||||
|
||||
private async connection(userId: string): Promise<{ token: string }> {
|
||||
private async connection(
|
||||
userId: string,
|
||||
): Promise<{ token: string; generation: string }> {
|
||||
const connection = await this.prisma.tbankConnection.findUnique({
|
||||
where: { userId },
|
||||
});
|
||||
if (!connection)
|
||||
throw new ConflictException({ code: 'TBANK_NOT_CONNECTED' });
|
||||
return { token: this.tokens.decrypt(connection.encryptedToken) };
|
||||
return {
|
||||
token: this.tokens.decrypt(connection.encryptedToken),
|
||||
generation: createHash('sha256')
|
||||
.update(connection.encryptedToken)
|
||||
.digest('base64url'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user