From fe7d7dc5f82c08308409153f8c9fc510b418af63 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sun, 7 Nov 2021 06:18:39 +0100 Subject: [PATCH 01/15] implemented most of updateUserInfos on Apollo also removed publisherId from updateUserInfos since this is now part of the login call. --- .../src/graphql/arg/UpdateUserInfosArgs.ts | 3 - .../graphql/model/UpdateUserInfosResponse.ts | 13 -- backend/src/graphql/resolver/UserResolver.ts | 178 +++++++++++------- frontend/src/graphql/mutations.js | 4 +- 4 files changed, 107 insertions(+), 91 deletions(-) delete mode 100644 backend/src/graphql/model/UpdateUserInfosResponse.ts diff --git a/backend/src/graphql/arg/UpdateUserInfosArgs.ts b/backend/src/graphql/arg/UpdateUserInfosArgs.ts index dca9ec4ab..0aee1f6f6 100644 --- a/backend/src/graphql/arg/UpdateUserInfosArgs.ts +++ b/backend/src/graphql/arg/UpdateUserInfosArgs.ts @@ -17,9 +17,6 @@ export default class UpdateUserInfosArgs { @Field({ nullable: true }) language?: string - @Field({ nullable: true }) - publisherId?: number - @Field({ nullable: true }) password?: string diff --git a/backend/src/graphql/model/UpdateUserInfosResponse.ts b/backend/src/graphql/model/UpdateUserInfosResponse.ts deleted file mode 100644 index 0e41f21cb..000000000 --- a/backend/src/graphql/model/UpdateUserInfosResponse.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { ObjectType, Field } from 'type-graphql' - -@ObjectType() -export class UpdateUserInfosResponse { - constructor(json: any) { - this.validValues = json.valid_values - } - - @Field(() => Number) - validValues: number -} diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 2ecd523e9..ef0347dec 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -7,7 +7,6 @@ import { getConnection, getCustomRepository } from 'typeorm' import CONFIG from '../../config' import { LoginViaVerificationCode } from '../model/LoginViaVerificationCode' import { SendPasswordResetEmailResponse } from '../model/SendPasswordResetEmailResponse' -import { UpdateUserInfosResponse } from '../model/UpdateUserInfosResponse' import { User } from '../model/User' import { User as DbUser } from '@entity/User' import encode from '../../jwt/encode' @@ -230,10 +229,10 @@ export class UserResolver { // Save publisherId if Elopage is not yet registered if (!user.hasElopage && publisherId) { user.publisherId = publisherId - await this.updateUserInfos( - { publisherId }, - { sessionId: result.data.session_id, pubKey: result.data.user.public_hex }, - ) + + const loginUser = await LoginUser.findOneOrFail({ email: userEntity.email }) + loginUser.publisherId = publisherId + loginUser.save() } const userSettingRepository = getCustomRepository(UserSettingRepository) @@ -446,7 +445,7 @@ export class UserResolver { } @Authorized() - @Mutation(() => UpdateUserInfosResponse) + @Mutation(() => Boolean) async updateUserInfos( @Args() { @@ -455,85 +454,120 @@ export class UserResolver { description, username, language, - publisherId, password, passwordNew, coinanimation, }: UpdateUserInfosArgs, @Ctx() context: any, - ): Promise { - const payload = { - session_id: context.sessionId, - update: { - 'User.first_name': firstName || undefined, - 'User.last_name': lastName || undefined, - 'User.description': description || undefined, - 'User.username': username || undefined, - 'User.language': language || undefined, - 'User.publisher_id': publisherId || undefined, - 'User.password': passwordNew || undefined, - 'User.password_old': password || undefined, - }, - } - let response: UpdateUserInfosResponse | undefined + ): Promise { const userRepository = getCustomRepository(UserRepository) + const userSettingRepository = getCustomRepository(UserSettingRepository) + const userEntity = await userRepository.findByPubkeyHex(context.pubKey) + const loginUser = await LoginUser.findOneOrFail({ email: userEntity.email }) - if ( - firstName || - lastName || - description || - username || - language || - publisherId || - passwordNew || - password - ) { - const result = await apiPost(CONFIG.LOGIN_API_URL + 'updateUserInfos', payload) - if (!result.success) throw new Error(result.data) - response = new UpdateUserInfosResponse(result.data) - - const userEntity = await userRepository.findByPubkeyHex(context.pubKey) - let userEntityChanged = false - if (firstName) { - userEntity.firstName = firstName - userEntityChanged = true - } - if (lastName) { - userEntity.lastName = lastName - userEntityChanged = true - } - if (username) { - userEntity.username = username - userEntityChanged = true - } - if (userEntityChanged) { - userRepository.save(userEntity).catch((error) => { - throw new Error(error) - }) - } + if (username) { + throw new Error('change username currently not supported!') + // TODO: this error was thrown on login_server whenever you tried to change the username + // to anything except "" which is an exception to the rules below. Those were defined + // aswell, even tho never used. + // ^[a-zA-Z][a-zA-Z0-9_-]*$ + // username must start with [a-z] or [A-Z] and than can contain also [0-9], - and _ + // username already used + // userEntity.username = username } - if (coinanimation !== undefined) { - // load user and balance - const userEntity = await userRepository.findByPubkeyHex(context.pubKey) + if (firstName) { + loginUser.firstName = firstName + userEntity.firstName = firstName + } - const userSettingRepository = getCustomRepository(UserSettingRepository) - userSettingRepository - .setOrUpdate(userEntity.id, Setting.COIN_ANIMATION, coinanimation.toString()) - .catch((error) => { - throw new Error(error) - }) + if (lastName) { + loginUser.lastName = lastName + userEntity.lastName = lastName + } - if (!response) { - response = new UpdateUserInfosResponse({ valid_values: 1 }) - } else { - response.validValues++ + if (description) { + loginUser.description = description + } + + // TODO: `disabled` can be set via this interface, the login_server allowed this. + // this means a user could disable his own account - sense? + + // TODO this requires language validation from createUser PR + // "User.language isn't a valid language" + if (language) { + loginUser.language = language + } + + if (password && passwordNew) { + throw new Error('Not implemented') + // CARE: password = password_old, passwordNew = password + // verify password + /* + if (isOldPasswordValid(updates, jsonErrorsArray)) + { + NotificationList errors; + if (!sm->checkPwdValidation(value.toString(), &errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) { + jsonErrorsArray.add("User.password isn't valid"); + jsonErrorsArray.add(errors.getErrorsArray()); + } + else + { + auto result_new_password = user->setNewPassword(value.toString()); + + switch (result_new_password) { + // 0 = new and current passwords are the same + // 1 = password changed, private key re-encrypted and saved into db + case 1: + extractet_values++; + password_changed = true; + break; + // 2 = password changed, only hash stored in db, couldn't load private key for re-encryption + case 2: + jsonErrorsArray.add("password changed, couldn't load private key for re-encryption"); + extractet_values++; + password_changed = true; + break; + // -1 = stored pubkey and private key didn't match + case -1: jsonErrorsArray.add("stored pubkey and private key didn't match"); break; + } + + } + } + */ + } + + const queryRunner = getConnection().createQueryRunner() + await queryRunner.connect() + await queryRunner.startTransaction('READ UNCOMMITTED') + + try { + if (coinanimation) { + // TODO transaction + userSettingRepository + .setOrUpdate(userEntity.id, Setting.COIN_ANIMATION, coinanimation.toString()) + .catch((error) => { + throw new Error(error) + }) } + + await queryRunner.manager.save(loginUser).catch((error) => { + throw new Error('error saving loginUser: ' + error) + }) + + await queryRunner.manager.save(userEntity).catch((error) => { + throw new Error('error saving user: ' + error) + }) + + await queryRunner.commitTransaction() + } catch (e) { + await queryRunner.rollbackTransaction() + throw e + } finally { + await queryRunner.release() } - if (!response) { - throw new Error('no valid response') - } - return response + + return true } @Query(() => Boolean) diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index a20367aa8..d1d3d583c 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -38,9 +38,7 @@ export const updateUserInfos = gql` passwordNew: $passwordNew language: $locale coinanimation: $coinanimation - ) { - validValues - } + ) } ` From 4ffa2b4ee1774904e22cc8981e521b544ce3ae7e Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sun, 7 Nov 2021 06:19:42 +0100 Subject: [PATCH 02/15] we will not implement disable here - it does not make sense that an user disables himself --- backend/src/graphql/resolver/UserResolver.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index ef0347dec..dc3e02d52 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -490,9 +490,6 @@ export class UserResolver { loginUser.description = description } - // TODO: `disabled` can be set via this interface, the login_server allowed this. - // this means a user could disable his own account - sense? - // TODO this requires language validation from createUser PR // "User.language isn't a valid language" if (language) { From f797017c9a156b781211e8ca09d5514dda489492 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 10 Nov 2021 20:23:47 +0100 Subject: [PATCH 03/15] have language check for changing language --- backend/src/graphql/resolver/UserResolver.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index dc3e02d52..37da362ae 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -490,9 +490,10 @@ export class UserResolver { loginUser.description = description } - // TODO this requires language validation from createUser PR - // "User.language isn't a valid language" if (language) { + if (!isLanguage(language)) { + throw new Error(`"${language}" isn't a valid language`) + } loginUser.language = language } From 7205eb2fae6f45601c283e24fd02439bb937a720 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 10 Nov 2021 20:34:14 +0100 Subject: [PATCH 04/15] transaction for coinanimation --- backend/src/graphql/resolver/UserResolver.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 37da362ae..174ecb4f9 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -541,11 +541,11 @@ export class UserResolver { try { if (coinanimation) { - // TODO transaction - userSettingRepository + queryRunner.manager + .getCustomRepository(UserSettingRepository) .setOrUpdate(userEntity.id, Setting.COIN_ANIMATION, coinanimation.toString()) .catch((error) => { - throw new Error(error) + throw new Error('error saving coinanimation: ' + error) }) } From 8b0c1feb3ec495206b66f558aa36583c173d495f Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 10 Nov 2021 23:47:37 +0100 Subject: [PATCH 05/15] change password and reencrypt private key when doing so. --- backend/src/graphql/resolver/UserResolver.ts | 61 ++++++++------------ 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 174ecb4f9..15720fd3f 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -173,7 +173,7 @@ const getEmailHash = (email: string): Buffer => { } const SecretKeyCryptographyEncrypt = (message: Buffer, encryptionKey: Buffer): Buffer => { - const encrypted = Buffer.alloc(sodium.crypto_secretbox_MACBYTES + message.length) + const encrypted = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES) const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) nonce.fill(31) // static nonce @@ -181,6 +181,16 @@ const SecretKeyCryptographyEncrypt = (message: Buffer, encryptionKey: Buffer): B return encrypted } +const SecretKeyCryptographyDecrypt = (encryptedMessage: Buffer, encryptionKey: Buffer): Buffer => { + const message = Buffer.alloc(encryptedMessage.length - sodium.crypto_secretbox_MACBYTES) + const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES) + nonce.fill(31) // static nonce + + sodium.crypto_secretbox_open_easy(message, encryptedMessage, nonce, encryptionKey) + + return message +} + @Resolver() export class UserResolver { @Query(() => User) @@ -498,41 +508,20 @@ export class UserResolver { } if (password && passwordNew) { - throw new Error('Not implemented') - // CARE: password = password_old, passwordNew = password - // verify password - /* - if (isOldPasswordValid(updates, jsonErrorsArray)) - { - NotificationList errors; - if (!sm->checkPwdValidation(value.toString(), &errors, LanguageManager::getInstance()->getFreeCatalog(LANG_EN))) { - jsonErrorsArray.add("User.password isn't valid"); - jsonErrorsArray.add(errors.getErrorsArray()); - } - else - { - auto result_new_password = user->setNewPassword(value.toString()); - - switch (result_new_password) { - // 0 = new and current passwords are the same - // 1 = password changed, private key re-encrypted and saved into db - case 1: - extractet_values++; - password_changed = true; - break; - // 2 = password changed, only hash stored in db, couldn't load private key for re-encryption - case 2: - jsonErrorsArray.add("password changed, couldn't load private key for re-encryption"); - extractet_values++; - password_changed = true; - break; - // -1 = stored pubkey and private key didn't match - case -1: jsonErrorsArray.add("stored pubkey and private key didn't match"); break; - } - - } - } - */ + // TODO: This had some error cases defined - like missing private key. This is no longer checked. + const oldPasswordHash = SecretKeyCryptographyCreateKey(loginUser.email, password) + if (loginUser.password !== oldPasswordHash[0].readBigUInt64LE()) { + throw new Error(`Old password is invalid`) + } + + const privKey = SecretKeyCryptographyDecrypt(loginUser.privKey, oldPasswordHash[1]) + + const newPasswordHash = SecretKeyCryptographyCreateKey(loginUser.email, passwordNew) // return short and long hash + const encryptedPrivkey = SecretKeyCryptographyEncrypt(privKey, newPasswordHash[1]) + + // Save new password hash and newly encrypted private key + loginUser.password = newPasswordHash[0].readBigInt64LE() + loginUser.privKey = encryptedPrivkey } const queryRunner = getConnection().createQueryRunner() From dc8091b60bfbd9086e84d95f2a30cf423de31d4b Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 10 Nov 2021 23:50:58 +0100 Subject: [PATCH 06/15] lint fix --- backend/src/graphql/resolver/UserResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 15720fd3f..4c9ec65e5 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -471,7 +471,6 @@ export class UserResolver { @Ctx() context: any, ): Promise { const userRepository = getCustomRepository(UserRepository) - const userSettingRepository = getCustomRepository(UserSettingRepository) const userEntity = await userRepository.findByPubkeyHex(context.pubKey) const loginUser = await LoginUser.findOneOrFail({ email: userEntity.email }) From 61786d9e5d0f1d0ad7a9d1eff47b7361fec71138 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 10 Nov 2021 23:52:44 +0100 Subject: [PATCH 07/15] another (unrelated) lint fix --- backend/src/util/sendEMail.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/src/util/sendEMail.ts b/backend/src/util/sendEMail.ts index e34597419..4c239980d 100644 --- a/backend/src/util/sendEMail.ts +++ b/backend/src/util/sendEMail.ts @@ -2,7 +2,12 @@ import { createTransport } from 'nodemailer' import CONFIG from '../config' -export const sendEMail = async (emailDef: any): Promise => { +export const sendEMail = async (emailDef: { + from: string + to: string + subject: string + text: string +}): Promise => { if (!CONFIG.EMAIL) { // eslint-disable-next-line no-console console.log('Emails are disabled via config') From d8835e37da7a916207172495cb3d57b440b116ad Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Thu, 11 Nov 2021 00:01:40 +0100 Subject: [PATCH 08/15] removed coverage --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9b10b7250..e09bdf8b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -394,7 +394,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 39 + min_coverage: 38 token: ${{ github.token }} ############################################################################## From e76646b327fff16c17250e552f6e4b812799b31c Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 10 Nov 2021 06:13:29 +0100 Subject: [PATCH 09/15] Withdrew the sessionId from the JWT. --- backend/src/graphql/directive/isAuthorized.ts | 12 +++--------- backend/src/jwt/decode.ts | 5 ----- backend/src/jwt/encode.ts | 5 ++--- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 77fe56ba1..d72f19456 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -13,15 +13,9 @@ const isAuthorized: AuthChecker = async ( ) => { if (context.token) { const decoded = decode(context.token) - if (decoded.sessionId && decoded.sessionId !== 0) { - const result = await apiGet( - `${CONFIG.LOGIN_API_URL}checkSessionState?session_id=${decoded.sessionId}`, - ) - context.sessionId = decoded.sessionId - context.pubKey = decoded.pubKey - context.setHeaders.push({ key: 'token', value: encode(decoded.sessionId, decoded.pubKey) }) - return result.success - } + context.pubKey = decoded.pubKey + context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) }) + return true } throw new Error('401 Unauthorized') } diff --git a/backend/src/jwt/decode.ts b/backend/src/jwt/decode.ts index 34b3ed836..6f09276b0 100644 --- a/backend/src/jwt/decode.ts +++ b/backend/src/jwt/decode.ts @@ -2,27 +2,22 @@ import jwt, { JwtPayload } from 'jsonwebtoken' import CONFIG from '../config/' interface CustomJwtPayload extends JwtPayload { - sessionId: number pubKey: Buffer } type DecodedJwt = { token: string - sessionId: number pubKey: Buffer } export default (token: string): DecodedJwt => { if (!token) throw new Error('401 Unauthorized') - let sessionId = null let pubKey = null try { const decoded = jwt.verify(token, CONFIG.JWT_SECRET) - sessionId = decoded.sessionId pubKey = decoded.pubKey return { token, - sessionId, pubKey, } } catch (err) { diff --git a/backend/src/jwt/encode.ts b/backend/src/jwt/encode.ts index fde28b467..ef062ad3a 100644 --- a/backend/src/jwt/encode.ts +++ b/backend/src/jwt/encode.ts @@ -5,10 +5,9 @@ import jwt from 'jsonwebtoken' import CONFIG from '../config/' // Generate an Access Token -export default function encode(sessionId: number, pubKey: Buffer): string { - const token = jwt.sign({ sessionId, pubKey }, CONFIG.JWT_SECRET, { +export default function encode(pubKey: Buffer): string { + const token = jwt.sign({ pubKey }, CONFIG.JWT_SECRET, { expiresIn: CONFIG.JWT_EXPIRES_IN, - subject: sessionId.toString(), }) return token } From cbc6570d657a358e953f8b746fc46587a31c79e8 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 11 Nov 2021 12:32:37 +0100 Subject: [PATCH 10/15] Encode doesn't need sessionId anymore. --- backend/src/graphql/resolver/TransactionResolver.ts | 2 +- backend/src/graphql/resolver/UserResolver.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 755955a7f..8b7b7cee1 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -516,7 +516,7 @@ export class TransactionResolver { } // validate recipient user - // TODO: the detour over the public key is unnecessary + // TODO: the detour over the public key is unnecessary sessionId is removed const recipiantPublicKey = await getPublicKey(email, context.sessionId) if (!recipiantPublicKey) { throw new Error('recipiant not known') diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 2ecd523e9..5184d550f 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -200,7 +200,7 @@ export class UserResolver { context.setHeaders.push({ key: 'token', - value: encode(result.data.session_id, result.data.user.public_hex), + value: encode(result.data.user.public_hex), }) const user = new User(result.data.user) // Hack: Database Field is not validated properly and not nullable From eb06b9a528f5fd777cc1096bde674603ba8734cf Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 00:09:30 +0100 Subject: [PATCH 11/15] Update backend/src/graphql/resolver/UserResolver.ts Co-authored-by: Hannes Heine --- backend/src/graphql/resolver/UserResolver.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 4c9ec65e5..58d38d0c5 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -240,9 +240,10 @@ export class UserResolver { if (!user.hasElopage && publisherId) { user.publisherId = publisherId - const loginUser = await LoginUser.findOneOrFail({ email: userEntity.email }) + const loginUserRepository = getCustomRepository(LoginUserRepository) + const loginUser = await loginUserRepository.findOneOrFail({ email: userEntity.email }) loginUser.publisherId = publisherId - loginUser.save() + loginUserRepository.save(loginUser) } const userSettingRepository = getCustomRepository(UserSettingRepository) From c9f167d07bf709046f2710e03dcb9d733d145acf Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 00:10:16 +0100 Subject: [PATCH 12/15] Update backend/src/graphql/resolver/UserResolver.ts Co-authored-by: Hannes Heine --- backend/src/graphql/resolver/UserResolver.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 58d38d0c5..baf39c562 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -473,7 +473,8 @@ export class UserResolver { ): Promise { const userRepository = getCustomRepository(UserRepository) const userEntity = await userRepository.findByPubkeyHex(context.pubKey) - const loginUser = await LoginUser.findOneOrFail({ email: userEntity.email }) + const loginUserRepository = getCustomRepository(LoginUserRepository) + const loginUser = await loginUserRepository.findOneOrFail({ email: userEntity.email }) if (username) { throw new Error('change username currently not supported!') From 4fccc19b684e5aad9bc9f781ed50519d0cdb20c0 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 00:13:44 +0100 Subject: [PATCH 13/15] missing import --- backend/src/graphql/resolver/UserResolver.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 489fc28d2..87f556264 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -29,6 +29,7 @@ import { LoginElopageBuys } from '@entity/LoginElopageBuys' import { LoginUserBackup } from '@entity/LoginUserBackup' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { sendEMail } from '../../util/sendEMail' +import { LoginUserRepository } from '../../typeorm/repository/LoginUser' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') From 540cbd0e1f3a598abca66af3ccdbeb1dbfc56c78 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 00:20:43 +0100 Subject: [PATCH 14/15] reimplement publisherId on updateUserInfos --- backend/src/graphql/arg/UpdateUserInfosArgs.ts | 3 +++ backend/src/graphql/resolver/UserResolver.ts | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/backend/src/graphql/arg/UpdateUserInfosArgs.ts b/backend/src/graphql/arg/UpdateUserInfosArgs.ts index 0aee1f6f6..dca9ec4ab 100644 --- a/backend/src/graphql/arg/UpdateUserInfosArgs.ts +++ b/backend/src/graphql/arg/UpdateUserInfosArgs.ts @@ -17,6 +17,9 @@ export default class UpdateUserInfosArgs { @Field({ nullable: true }) language?: string + @Field({ nullable: true }) + publisherId?: number + @Field({ nullable: true }) password?: string diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 87f556264..5c4625938 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -466,6 +466,7 @@ export class UserResolver { description, username, language, + publisherId, password, passwordNew, coinanimation, @@ -526,6 +527,11 @@ export class UserResolver { loginUser.privKey = encryptedPrivkey } + // Save publisherId only if Elopage is not yet registered + if (publisherId && !(await this.hasElopage(context))) { + loginUser.publisherId = publisherId + } + const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('READ UNCOMMITTED') From f09c3b4964605ae4e66a6149a79e58a909efdf44 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 00:40:16 +0100 Subject: [PATCH 15/15] replace implementation of `getPublicKey` to no longer require the sessionId. Furthermore the call now no longer calls `getUserInfos` on the `login_server` but just queries the database itself --- .../graphql/resolver/TransactionResolver.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 755955a7f..968ce9d4c 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -33,6 +33,7 @@ import { calculateDecay, calculateDecayWithInterval } from '../../util/decay' import { TransactionTypeId } from '../enum/TransactionTypeId' import { TransactionType } from '../enum/TransactionType' import { hasUserAmount, isHexPublicKey } from '../../util/validate' +import { LoginUserRepository } from '../../typeorm/repository/LoginUser' /* # Test @@ -451,15 +452,15 @@ async function addUserTransaction( }) } -async function getPublicKey(email: string, sessionId: number): Promise { - const result = await apiPost(CONFIG.LOGIN_API_URL + 'getUserInfos', { - session_id: sessionId, - email, - ask: ['user.pubkeyhex'], - }) - if (result.success) { - return result.data.userData.pubkeyhex +async function getPublicKey(email: string): Promise { + const loginUserRepository = getCustomRepository(LoginUserRepository) + const loginUser = await loginUserRepository.findOne({ email: email }) + // User not found + if (!loginUser) { + return null } + + return loginUser.pubKey.toString('hex') } @Resolver() @@ -517,7 +518,7 @@ export class TransactionResolver { // validate recipient user // TODO: the detour over the public key is unnecessary - const recipiantPublicKey = await getPublicKey(email, context.sessionId) + const recipiantPublicKey = await getPublicKey(email) if (!recipiantPublicKey) { throw new Error('recipiant not known') }