From ac11d1fa6019b386112c4beef96908638d8a1193 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 17 Mar 2022 09:55:15 +0100 Subject: [PATCH 1/7] store user entity created on authentication check in context to avoid further DB calls --- backend/src/graphql/directive/isAuthorized.ts | 1 + backend/src/graphql/resolver/UserResolver.ts | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 159a1614c..84756c45a 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -35,6 +35,7 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { const userRepository = await getCustomRepository(UserRepository) try { const user = await userRepository.findByPubkeyHex(context.pubKey) + context.user = user const countServerUsers = await ServerUser.count({ email: user.email }) context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER } catch { diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 9896ddc97..39a983c2b 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -14,7 +14,6 @@ import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' import { klicktippNewsletterStateMiddleware } from '@/middleware/klicktippMiddleware' import { UserSettingRepository } from '@repository/UserSettingRepository' import { Setting } from '@enum/Setting' -import { UserRepository } from '@repository/User' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { sendResetPasswordEmail } from '@/mailer/sendResetPasswordEmail' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' @@ -214,8 +213,7 @@ export class UserResolver { @UseMiddleware(klicktippNewsletterStateMiddleware) async verifyLogin(@Ctx() context: any): Promise { // TODO refactor and do not have duplicate code with login(see below) - const userRepository = getCustomRepository(UserRepository) - const userEntity = await userRepository.findByPubkeyHex(context.pubKey) + const userEntity = context.user const user = new User(userEntity) // user.pubkey = userEntity.pubKey.toString('hex') // Elopage Status & Stored PublisherId @@ -585,8 +583,7 @@ export class UserResolver { }: UpdateUserInfosArgs, @Ctx() context: any, ): Promise { - const userRepository = getCustomRepository(UserRepository) - const userEntity = await userRepository.findByPubkeyHex(context.pubKey) + const userEntity = context.user if (firstName) { userEntity.firstName = firstName @@ -664,8 +661,7 @@ export class UserResolver { @Authorized([RIGHTS.HAS_ELOPAGE]) @Query(() => Boolean) async hasElopage(@Ctx() context: any): Promise { - const userRepository = getCustomRepository(UserRepository) - const userEntity = await userRepository.findByPubkeyHex(context.pubKey).catch() + const userEntity = context.user if (!userEntity) { return false } From fd9292b3d5ca6f97658f840d425e086ad4f1694b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 17 Mar 2022 09:57:19 +0100 Subject: [PATCH 2/7] user context in admin interface --- backend/src/graphql/resolver/AdminResolver.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index f116c3968..f0210dc8d 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -129,8 +129,7 @@ export class AdminResolver { throw new Error(`Could not find user with userId: ${userId}`) } // moderator user disabled own account? - const userRepository = getCustomRepository(UserRepository) - const moderatorUser = await userRepository.findByPubkeyHex(context.pubKey) + const moderatorUser = context.user if (moderatorUser.id === userId) { throw new Error('Moderator can not delete his own account!') } @@ -294,8 +293,7 @@ export class AdminResolver { @Mutation(() => Boolean) async confirmPendingCreation(@Arg('id') id: number, @Ctx() context: any): Promise { const pendingCreation = await AdminPendingCreation.findOneOrFail(id) - const userRepository = getCustomRepository(UserRepository) - const moderatorUser = await userRepository.findByPubkeyHex(context.pubKey) + const moderatorUser = context.user if (moderatorUser.id === pendingCreation.userId) throw new Error('Moderator can not confirm own pending creation') From b44ef7175616a9956eec4e7f0d9d49306fa76425 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 17 Mar 2022 10:05:07 +0100 Subject: [PATCH 3/7] no double DB calls to get user from db in resolvers --- backend/src/graphql/resolver/BalanceResolver.ts | 6 +----- backend/src/graphql/resolver/GdtResolver.ts | 5 +---- .../graphql/resolver/TransactionLinkResolver.ts | 14 ++++---------- .../src/graphql/resolver/TransactionResolver.ts | 3 +-- 4 files changed, 7 insertions(+), 21 deletions(-) diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 12d5b2ba4..09d2fdc92 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -2,9 +2,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Resolver, Query, Ctx, Authorized } from 'type-graphql' -import { getCustomRepository } from '@dbTools/typeorm' import { Balance } from '@model/Balance' -import { UserRepository } from '@repository/User' import { calculateDecay } from '@/util/decay' import { RIGHTS } from '@/auth/RIGHTS' import { Transaction } from '@entity/Transaction' @@ -16,9 +14,7 @@ export class BalanceResolver { @Query(() => Balance) async balance(@Ctx() context: any): Promise { // load user and balance - const userRepository = getCustomRepository(UserRepository) - - const user = await userRepository.findByPubkeyHex(context.pubKey) + const { user } = context const now = new Date() const lastTransaction = await Transaction.findOne( diff --git a/backend/src/graphql/resolver/GdtResolver.ts b/backend/src/graphql/resolver/GdtResolver.ts index c8c4cb331..26ae9b210 100644 --- a/backend/src/graphql/resolver/GdtResolver.ts +++ b/backend/src/graphql/resolver/GdtResolver.ts @@ -2,12 +2,10 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Resolver, Query, Args, Ctx, Authorized, Arg } from 'type-graphql' -import { getCustomRepository } from '@dbTools/typeorm' import CONFIG from '@/config' import { GdtEntryList } from '@model/GdtEntryList' import Paginated from '@arg/Paginated' import { apiGet } from '@/apis/HttpRequest' -import { UserRepository } from '@repository/User' import { Order } from '@enum/Order' import { RIGHTS } from '@/auth/RIGHTS' @@ -22,8 +20,7 @@ export class GdtResolver { @Ctx() context: any, ): Promise { // load user - const userRepository = getCustomRepository(UserRepository) - const userEntity = await userRepository.findByPubkeyHex(context.pubKey) + const userEntity = context.user try { const resultGDT = await apiGet( diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 9e2af6111..ead82e182 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -2,11 +2,9 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query } from 'type-graphql' -import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLink } from '@model/TransactionLink' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { User as dbUser } from '@entity/User' -import { UserRepository } from '@repository/User' import TransactionLinkArgs from '@arg/TransactionLinkArgs' import Paginated from '@arg/Paginated' import { calculateBalance } from '@/util/validate' @@ -42,8 +40,7 @@ export class TransactionLinkResolver { @Args() { amount, memo }: TransactionLinkArgs, @Ctx() context: any, ): Promise { - const userRepository = getCustomRepository(UserRepository) - const user = await userRepository.findByPubkeyHex(context.pubKey) + const { user } = context const createdDate = new Date() const validUntil = transactionLinkExpireDate(createdDate) @@ -74,8 +71,7 @@ export class TransactionLinkResolver { @Authorized([RIGHTS.DELETE_TRANSACTION_LINK]) @Mutation(() => Boolean) async deleteTransactionLink(@Arg('id') id: number, @Ctx() context: any): Promise { - const userRepository = getCustomRepository(UserRepository) - const user = await userRepository.findByPubkeyHex(context.pubKey) + const { user } = context const transactionLink = await dbTransactionLink.findOne({ id }) if (!transactionLink) { @@ -116,8 +112,7 @@ export class TransactionLinkResolver { { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, @Ctx() context: any, ): Promise { - const userRepository = getCustomRepository(UserRepository) - const user = await userRepository.findByPubkeyHex(context.pubKey) + const { user } = context // const now = new Date() const transactionLinks = await dbTransactionLink.find({ where: { @@ -137,8 +132,7 @@ export class TransactionLinkResolver { @Authorized([RIGHTS.REDEEM_TRANSACTION_LINK]) @Mutation(() => Boolean) async redeemTransactionLink(@Arg('id') id: number, @Ctx() context: any): Promise { - const userRepository = getCustomRepository(UserRepository) - const user = await userRepository.findByPubkeyHex(context.pubKey) + const { user } = context const transactionLink = await dbTransactionLink.findOneOrFail({ id }) const linkedUser = await dbUser.findOneOrFail({ id: transactionLink.userId }) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index f64ba19e9..258ea9da6 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -256,8 +256,7 @@ export class TransactionResolver { @Ctx() context: any, ): Promise { // TODO this is subject to replay attacks - const userRepository = getCustomRepository(UserRepository) - const senderUser = await userRepository.findByPubkeyHex(context.pubKey) + const senderUser = context.user if (senderUser.pubKey.length !== 32) { throw new Error('invalid sender public key') } From 577ca00c460f2f30b77df77029f93f91f38d926d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 17 Mar 2022 10:46:29 +0100 Subject: [PATCH 4/7] refactor transaction list query, do not allow user id an only creations as args any more. this query only return the transactions of the logged in user --- backend/src/graphql/arg/Paginated.ts | 6 ------ .../graphql/resolver/TransactionResolver.ts | 19 +++---------------- frontend/src/graphql/queries.js | 14 ++------------ 3 files changed, 5 insertions(+), 34 deletions(-) diff --git a/backend/src/graphql/arg/Paginated.ts b/backend/src/graphql/arg/Paginated.ts index f365165de..97326caf2 100644 --- a/backend/src/graphql/arg/Paginated.ts +++ b/backend/src/graphql/arg/Paginated.ts @@ -11,10 +11,4 @@ export default class Paginated { @Field(() => Order, { nullable: true }) order?: Order - - @Field(() => Boolean, { nullable: true }) - onlyCreations?: boolean - - @Field(() => Int, { nullable: true }) - userId?: number } diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 258ea9da6..03640817f 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -17,7 +17,6 @@ import Paginated from '@arg/Paginated' import { Order } from '@enum/Order' -import { UserRepository } from '@repository/User' import { TransactionRepository } from '@repository/Transaction' import { TransactionLinkRepository } from '@repository/TransactionLink' @@ -131,22 +130,11 @@ export class TransactionResolver { @Query(() => TransactionList) async transactionList( @Args() - { - currentPage = 1, - pageSize = 25, - order = Order.DESC, - onlyCreations = false, - userId, - }: Paginated, + { currentPage = 1, pageSize = 25, order = Order.DESC }: Paginated, @Ctx() context: any, ): Promise { const now = new Date() - // find user - const userRepository = getCustomRepository(UserRepository) - // TODO: separate those usecases - this is a security issue - const user = userId - ? await userRepository.findOneOrFail({ id: userId }, { withDeleted: true }) - : await userRepository.findByPubkeyHex(context.pubKey) + const user = context.user // find current balance const lastTransaction = await dbTransaction.findOne( @@ -182,7 +170,6 @@ export class TransactionResolver { pageSize, offset, order, - onlyCreations, ) // find involved users; I am involved @@ -208,7 +195,7 @@ export class TransactionResolver { await transactionLinkRepository.summary(user.id, now) // decay & link transactions - if (!onlyCreations && currentPage === 1 && order === Order.DESC) { + if (currentPage === 1 && order === Order.DESC) { transactions.push( virtualDecayTransaction(lastTransaction.balance, lastTransaction.balanceDate, now, self), ) diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 5887d585a..c2efe34d8 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -43,18 +43,8 @@ export const logout = gql` ` export const transactionsQuery = gql` - query( - $currentPage: Int = 1 - $pageSize: Int = 25 - $order: Order = DESC - $onlyCreations: Boolean = false - ) { - transactionList( - currentPage: $currentPage - pageSize: $pageSize - order: $order - onlyCreations: $onlyCreations - ) { + query($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) { + transactionList(currentPage: $currentPage, pageSize: $pageSize, order: $order) { balanceGDT count linkCount From f21e0ed038340e5999af830b49a1dc74707d60db Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 17 Mar 2022 11:20:26 +0100 Subject: [PATCH 5/7] only creations transaction list with admin rights --- .../CreationTransactionListFormular.vue | 7 ++- admin/src/graphql/creationTransactionList.js | 22 ++++++++ admin/src/graphql/transactionList.js | 31 ------------ backend/src/auth/RIGHTS.ts | 1 + backend/src/graphql/resolver/AdminResolver.ts | 50 +++++++++++++++---- 5 files changed, 65 insertions(+), 46 deletions(-) create mode 100644 admin/src/graphql/creationTransactionList.js delete mode 100644 admin/src/graphql/transactionList.js diff --git a/admin/src/components/CreationTransactionListFormular.vue b/admin/src/components/CreationTransactionListFormular.vue index 0b78ca4b8..ce2b136a4 100644 --- a/admin/src/components/CreationTransactionListFormular.vue +++ b/admin/src/components/CreationTransactionListFormular.vue @@ -5,7 +5,7 @@