From 8c9b4614b2d480c2e599d4f175ad7de25b412ae8 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 29 Jun 2023 12:12:49 +0200 Subject: [PATCH] Surrond the check if link is correct with the new semafore. --- .../resolver/TransactionLinkResolver.ts | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index d6649814a..a2cdabd81 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -33,6 +33,7 @@ import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { calculateDecay } from '@/util/decay' +import { TRANSACTION_LINK_LOCK } from '@/util/TRANSACTION_LINK_LOCK' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { fullName } from '@/util/utilities' import { calculateBalance } from '@/util/validate' @@ -302,49 +303,49 @@ export class TransactionLinkResolver { return true } else { const now = new Date() - const transactionLink = await DbTransactionLink.findOne({ code }) - if (!transactionLink) { - throw new LogError('Transaction link not found', code) + const releaseLinkLock = await TRANSACTION_LINK_LOCK.acquire() + try { + const transactionLink = await DbTransactionLink.findOne({ code }) + if (!transactionLink) { + throw new LogError('Transaction link not found', code) + } + + const linkedUser = await DbUser.findOne( + { id: transactionLink.userId }, + { relations: ['emailContact'] }, + ) + + if (!linkedUser) { + throw new LogError('Linked user not found for given link', transactionLink.userId) + } + + if (user.id === linkedUser.id) { + throw new LogError('Cannot redeem own transaction link', user.id) + } + + if (transactionLink.validUntil.getTime() < now.getTime()) { + throw new LogError('Transaction link is not valid anymore', transactionLink.validUntil) + } + + if (transactionLink.redeemedBy) { + throw new LogError('Transaction link already redeemed', transactionLink.redeemedBy) + } + await executeTransaction( + transactionLink.amount, + transactionLink.memo, + linkedUser, + user, + transactionLink, + ) + await EVENT_TRANSACTION_LINK_REDEEM( + user, + { id: transactionLink.userId } as DbUser, + transactionLink, + transactionLink.amount, + ) + } finally { + releaseLinkLock() } - - const linkedUser = await DbUser.findOne( - { id: transactionLink.userId }, - { relations: ['emailContact'] }, - ) - - if (!linkedUser) { - throw new LogError('Linked user not found for given link', transactionLink.userId) - } - - if (user.id === linkedUser.id) { - throw new LogError('Cannot redeem own transaction link', user.id) - } - - // TODO: The now check should be done within the semaphore lock, - // since the program might wait a while till it is ready to proceed - // writing the transaction. - if (transactionLink.validUntil.getTime() < now.getTime()) { - throw new LogError('Transaction link is not valid anymore', transactionLink.validUntil) - } - - if (transactionLink.redeemedBy) { - throw new LogError('Transaction link already redeemed', transactionLink.redeemedBy) - } - - await executeTransaction( - transactionLink.amount, - transactionLink.memo, - linkedUser, - user, - transactionLink, - ) - await EVENT_TRANSACTION_LINK_REDEEM( - user, - { id: transactionLink.userId } as DbUser, - transactionLink, - transactionLink.amount, - ) - return true } }