diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index c314b5bb7..7430868b1 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -23,6 +23,7 @@ import { calculateDecay } from '../../util/decay' import { AdminPendingCreation } from '@entity/AdminPendingCreation' import { hasElopageBuys } from '../../util/hasElopageBuys' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' +import { User } from '@entity/User' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? @@ -82,8 +83,13 @@ export class AdminResolver { async createPendingCreation( @Args() { email, amount, memo, creationDate, moderator }: CreatePendingCreationArgs, ): Promise { - const userRepository = getCustomRepository(UserRepository) - const user = await userRepository.findByEmail(email) + const user = await User.findOne({ email }, { withDeleted: true }) + if (!user) { + throw new Error(`Could not find user with email: ${email}`) + } + if (user.deletedAt) { + throw new Error('This user was deleted. Cannot make a creation.') + } if (!user.emailChecked) { throw new Error('Creation could not be saved, Email is not activated') } @@ -134,8 +140,13 @@ export class AdminResolver { async updatePendingCreation( @Args() { id, email, amount, memo, creationDate, moderator }: UpdatePendingCreationArgs, ): Promise { - const userRepository = getCustomRepository(UserRepository) - const user = await userRepository.findByEmail(email) + const user = await User.findOne({ email }, { withDeleted: true }) + if (!user) { + throw new Error(`Could not find user with email: ${email}`) + } + if (user.deletedAt) { + throw new Error(`User was deleted (${email})`) + } const pendingCreationToUpdate = await AdminPendingCreation.findOneOrFail({ id }) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 622bf37fe..8d9e0c6c3 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -272,16 +272,6 @@ async function addUserTransaction( }) } -async function getPublicKey(email: string): Promise { - const user = await dbUser.findOne({ email: email }) - // User not found - if (!user) { - return null - } - - return user.pubKey.toString('hex') -} - @Resolver() export class TransactionResolver { @Authorized([RIGHTS.TRANSACTION_LIST]) @@ -301,7 +291,7 @@ export class TransactionResolver { const userRepository = getCustomRepository(UserRepository) let userEntity: dbUser | undefined if (userId) { - userEntity = await userRepository.findOneOrFail({ id: userId }) + userEntity = await userRepository.findOneOrFail({ id: userId }, { withDeleted: true }) } else { userEntity = await userRepository.findByPubkeyHex(context.pubKey) } @@ -357,18 +347,15 @@ export class TransactionResolver { // validate recipient user // TODO: the detour over the public key is unnecessary - const recipiantPublicKey = await getPublicKey(email) - if (!recipiantPublicKey) { + const recipientUser = await dbUser.findOne({ email: email }, { withDeleted: true }) + if (!recipientUser) { throw new Error('recipient not known') } - if (!isHexPublicKey(recipiantPublicKey)) { - throw new Error('invalid recipiant public key') + if (recipientUser.deletedAt) { + throw new Error('The recipient account was deleted') } - const recipiantUser = await userRepository.findByPubkeyHex(recipiantPublicKey) - if (!recipiantUser) { - throw new Error('Cannot find recipiant user by local send coins transaction') - } else if (recipiantUser.deletedAt) { - throw new Error('recipiant user account is disabled') + if (!isHexPublicKey(recipientUser.pubKey.toString('hex'))) { + throw new Error('invalid recipient public key') } // validate amount @@ -405,7 +392,7 @@ export class TransactionResolver { // Insert Transaction: recipient + amount const recipiantUserTransactionBalance = await addUserTransaction( - recipiantUser, + recipientUser, transaction, centAmount, queryRunner, @@ -421,7 +408,7 @@ export class TransactionResolver { // Update Balance: recipiant + amount const recipiantStateBalance = await updateStateBalance( - recipiantUser, + recipientUser, centAmount, transaction.received, queryRunner, @@ -439,8 +426,8 @@ export class TransactionResolver { transactionSendCoin.transactionId = transaction.id transactionSendCoin.userId = senderUser.id transactionSendCoin.senderPublic = senderUser.pubKey - transactionSendCoin.recipiantUserId = recipiantUser.id - transactionSendCoin.recipiantPublic = Buffer.from(recipiantPublicKey, 'hex') + transactionSendCoin.recipiantUserId = recipientUser.id + transactionSendCoin.recipiantPublic = recipientUser.pubKey transactionSendCoin.amount = centAmount transactionSendCoin.senderFinalBalance = senderStateBalance.amount await queryRunner.manager.save(transactionSendCoin).catch((error) => { @@ -474,9 +461,9 @@ export class TransactionResolver { await sendTransactionReceivedEmail({ senderFirstName: senderUser.firstName, senderLastName: senderUser.lastName, - recipientFirstName: recipiantUser.firstName, - recipientLastName: recipiantUser.lastName, - email: recipiantUser.email, + recipientFirstName: recipientUser.firstName, + recipientLastName: recipientUser.lastName, + email: recipientUser.email, amount, memo, }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 5bc30f6b4..fdae2a14e 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -250,9 +250,12 @@ export class UserResolver { @Ctx() context: any, ): Promise { email = email.trim().toLowerCase() - const dbUser = await DbUser.findOneOrFail({ email }).catch(() => { + const dbUser = await DbUser.findOneOrFail({ email }, { withDeleted: true }).catch(() => { throw new Error('No user with this credentials') }) + if (dbUser.deletedAt) { + throw new Error('This user was permanently disabled. Contact support for questions.') + } if (!dbUser.emailChecked) { throw new Error('User email not validated') } @@ -335,9 +338,9 @@ export class UserResolver { // Validate email unique // TODO: i can register an email in upper/lower case twice - const userRepository = getCustomRepository(UserRepository) - const usersFound = await userRepository.count({ email }) - if (usersFound !== 0) { + // TODO we cannot use repository.count(), since it does not allow to specify if you want to include the soft deletes + const userFound = await DbUser.findOne({ email }, { withDeleted: true }) + if (userFound) { // TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent. throw new Error(`User already exists.`) } diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index 59d6ff465..88467fc95 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -14,10 +14,6 @@ export class UserRepository extends Repository { return await this.findByPubkeyHex(pubKeyString) } - async findByEmail(email: string): Promise { - return this.createQueryBuilder('user').where('user.email = :email', { email }).getOneOrFail() - } - async getUsersIndiced(userIds: number[]): Promise { if (!userIds.length) return [] const users = await this.createQueryBuilder('user') @@ -33,6 +29,7 @@ export class UserRepository extends Repository { async findBySearchCriteria(searchCriteria: string): Promise { return await this.createQueryBuilder('user') + .withDeleted() .where( 'user.firstName like :name or user.lastName like :lastName or user.email like :email', {