mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into add-model-entities
This commit is contained in:
commit
5e3e139a23
@ -51,7 +51,6 @@ const email = {
|
||||
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx',
|
||||
EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com',
|
||||
EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587',
|
||||
|
||||
EMAIL_LINK_VERIFICATION:
|
||||
process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/vue/checkEmail/$1',
|
||||
}
|
||||
|
||||
@ -2,9 +2,6 @@
|
||||
|
||||
import { AuthChecker } from 'type-graphql'
|
||||
|
||||
import CONFIG from '../../config'
|
||||
import { apiGet } from '../../apis/HttpRequest'
|
||||
|
||||
import decode from '../../jwt/decode'
|
||||
import encode from '../../jwt/encode'
|
||||
|
||||
@ -13,7 +10,7 @@ const isAuthorized: AuthChecker<any> = async (
|
||||
) => {
|
||||
if (context.token) {
|
||||
const decoded = decode(context.token)
|
||||
context.pubKey = decoded.pubKey
|
||||
context.pubKey = Buffer.from(decoded.pubKey).toString('hex')
|
||||
context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) })
|
||||
return true
|
||||
}
|
||||
|
||||
@ -10,15 +10,17 @@ export class User {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number
|
||||
*/
|
||||
constructor(json: any) {
|
||||
this.email = json.email
|
||||
this.firstName = json.first_name
|
||||
this.lastName = json.last_name
|
||||
this.username = json.username
|
||||
this.description = json.description
|
||||
this.pubkey = json.public_hex
|
||||
this.language = json.language
|
||||
this.publisherId = json.publisher_id
|
||||
constructor(json?: any) {
|
||||
if (json) {
|
||||
this.email = json.email
|
||||
this.firstName = json.first_name
|
||||
this.lastName = json.last_name
|
||||
this.username = json.username
|
||||
this.description = json.description
|
||||
this.pubkey = json.public_hex
|
||||
this.language = json.language
|
||||
this.publisherId = json.publisher_id
|
||||
}
|
||||
}
|
||||
|
||||
@Field(() => String)
|
||||
|
||||
@ -613,9 +613,6 @@ export class TransactionResolver {
|
||||
await queryRunner.commitTransaction()
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw e
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
// TODO: This is broken code - we should never correct an autoincrement index in production
|
||||
// according to dario it is required tho to properly work. The index of the table is used as
|
||||
// index for the transaction which requires a chain without gaps
|
||||
@ -627,6 +624,9 @@ export class TransactionResolver {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('problems with reset auto increment: %o', error)
|
||||
})
|
||||
throw e
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
}
|
||||
// send notification email
|
||||
// TODO: translate
|
||||
|
||||
@ -22,14 +22,14 @@ import {
|
||||
} from '../../middleware/klicktippMiddleware'
|
||||
import { CheckEmailResponse } from '../model/CheckEmailResponse'
|
||||
import { UserSettingRepository } from '../../typeorm/repository/UserSettingRepository'
|
||||
import { LoginUserRepository } from '../../typeorm/repository/LoginUser'
|
||||
import { Setting } from '../enum/Setting'
|
||||
import { UserRepository } from '../../typeorm/repository/User'
|
||||
import { LoginUser } from '@entity/LoginUser'
|
||||
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'
|
||||
import { LoginElopageBuysRepository } from '../../typeorm/repository/LoginElopageBuys'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const sodium = require('sodium-native')
|
||||
@ -201,33 +201,32 @@ export class UserResolver {
|
||||
@Ctx() context: any,
|
||||
): Promise<User> {
|
||||
email = email.trim().toLowerCase()
|
||||
const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password })
|
||||
|
||||
// if there is no user, throw an authentication error
|
||||
if (!result.success) {
|
||||
throw new Error(result.data)
|
||||
}
|
||||
|
||||
context.setHeaders.push({
|
||||
key: 'token',
|
||||
value: encode(result.data.user.public_hex),
|
||||
// const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password })
|
||||
// UnsecureLogin
|
||||
const loginUserRepository = getCustomRepository(LoginUserRepository)
|
||||
const loginUser = await loginUserRepository.findByEmail(email).catch(() => {
|
||||
throw new Error('No user with this credentials')
|
||||
})
|
||||
const user = new User(result.data.user)
|
||||
// Hack: Database Field is not validated properly and not nullable
|
||||
if (user.publisherId === 0) {
|
||||
user.publisherId = undefined
|
||||
const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash
|
||||
const loginUserPassword = BigInt(loginUser.password.toString())
|
||||
if (loginUserPassword !== passwordHash[0].readBigUInt64LE()) {
|
||||
throw new Error('No user with this credentials')
|
||||
}
|
||||
user.hasElopage = result.data.hasElopage
|
||||
// read additional settings from settings table
|
||||
// TODO: If user has no pubKey Create it again and update user.
|
||||
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
let userEntity: void | DbUser
|
||||
userEntity = await userRepository.findByPubkeyHex(user.pubkey).catch(() => {
|
||||
const loginUserPubKey = loginUser.pubKey
|
||||
const loginUserPubKeyString = loginUserPubKey.toString('hex')
|
||||
userEntity = await userRepository.findByPubkeyHex(loginUserPubKeyString).catch(() => {
|
||||
// User not stored in state_users
|
||||
// TODO: Check with production data - email is unique which can cause problems
|
||||
userEntity = new DbUser()
|
||||
userEntity.firstName = user.firstName
|
||||
userEntity.lastName = user.lastName
|
||||
userEntity.username = user.username
|
||||
userEntity.email = user.email
|
||||
userEntity.pubkey = Buffer.from(user.pubkey, 'hex')
|
||||
userEntity.firstName = loginUser.firstName
|
||||
userEntity.lastName = loginUser.lastName
|
||||
userEntity.username = loginUser.username
|
||||
userEntity.email = loginUser.email
|
||||
userEntity.pubkey = loginUser.pubKey
|
||||
|
||||
userRepository.save(userEntity).catch(() => {
|
||||
throw new Error('error by save userEntity')
|
||||
@ -237,16 +236,28 @@ export class UserResolver {
|
||||
throw new Error('error with cannot happen')
|
||||
}
|
||||
|
||||
// Save publisherId if Elopage is not yet registered
|
||||
const user = new User()
|
||||
user.email = email
|
||||
user.firstName = loginUser.firstName
|
||||
user.lastName = loginUser.lastName
|
||||
user.username = loginUser.username
|
||||
user.description = loginUser.description
|
||||
user.pubkey = loginUserPubKeyString
|
||||
user.language = loginUser.language
|
||||
|
||||
// Elopage Status & Stored PublisherId
|
||||
user.hasElopage = await this.hasElopage({ pubKey: loginUserPubKeyString })
|
||||
if (!user.hasElopage && publisherId) {
|
||||
user.publisherId = publisherId
|
||||
|
||||
// TODO: Check if we can use updateUserInfos
|
||||
// await this.updateUserInfos({ publisherId }, { pubKey: loginUser.pubKey })
|
||||
const loginUserRepository = getCustomRepository(LoginUserRepository)
|
||||
const loginUser = await loginUserRepository.findOneOrFail({ email: userEntity.email })
|
||||
loginUser.publisherId = publisherId
|
||||
loginUserRepository.save(loginUser)
|
||||
}
|
||||
|
||||
// coinAnimation
|
||||
const userSettingRepository = getCustomRepository(UserSettingRepository)
|
||||
const coinanimation = await userSettingRepository
|
||||
.readBoolean(userEntity.id, Setting.COIN_ANIMATION)
|
||||
@ -254,6 +265,12 @@ export class UserResolver {
|
||||
throw new Error(error)
|
||||
})
|
||||
user.coinanimation = coinanimation
|
||||
|
||||
context.setHeaders.push({
|
||||
key: 'token',
|
||||
value: encode(loginUser.pubKey),
|
||||
})
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
@ -537,7 +554,7 @@ export class UserResolver {
|
||||
await queryRunner.startTransaction('READ UNCOMMITTED')
|
||||
|
||||
try {
|
||||
if (coinanimation) {
|
||||
if (coinanimation !== null && coinanimation !== undefined) {
|
||||
queryRunner.manager
|
||||
.getCustomRepository(UserSettingRepository)
|
||||
.setOrUpdate(userEntity.id, Setting.COIN_ANIMATION, coinanimation.toString())
|
||||
@ -609,7 +626,8 @@ export class UserResolver {
|
||||
return false
|
||||
}
|
||||
|
||||
const elopageBuyCount = await LoginElopageBuys.count({ payerEmail: userEntity.email })
|
||||
const loginElopageBuysRepository = getCustomRepository(LoginElopageBuysRepository)
|
||||
const elopageBuyCount = await loginElopageBuysRepository.count({ payerEmail: userEntity.email })
|
||||
return elopageBuyCount > 0
|
||||
}
|
||||
}
|
||||
|
||||
5
backend/src/typeorm/repository/LoginElopageBuys.ts
Normal file
5
backend/src/typeorm/repository/LoginElopageBuys.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { EntityRepository, Repository } from 'typeorm'
|
||||
import { LoginElopageBuys } from '@entity/LoginElopageBuys'
|
||||
|
||||
@EntityRepository(LoginElopageBuys)
|
||||
export class LoginElopageBuysRepository extends Repository<LoginElopageBuys> {}
|
||||
@ -2,4 +2,10 @@ import { EntityRepository, Repository } from 'typeorm'
|
||||
import { LoginUser } from '@entity/LoginUser'
|
||||
|
||||
@EntityRepository(LoginUser)
|
||||
export class LoginUserRepository extends Repository<LoginUser> {}
|
||||
export class LoginUserRepository extends Repository<LoginUser> {
|
||||
async findByEmail(email: string): Promise<LoginUser> {
|
||||
return this.createQueryBuilder('loginUser')
|
||||
.where('loginUser.email = :email', { email })
|
||||
.getOneOrFail()
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,15 @@ export class UserRepository extends Repository<User> {
|
||||
.getOneOrFail()
|
||||
}
|
||||
|
||||
async findByPubkeyHexBuffer(pubkeyHexBuffer: Buffer): Promise<User> {
|
||||
const pubKeyString = pubkeyHexBuffer.toString('hex')
|
||||
return await this.findByPubkeyHex(pubKeyString)
|
||||
}
|
||||
|
||||
async findByEmail(email: string): Promise<User> {
|
||||
return this.createQueryBuilder('user').where('user.email = :email', { email }).getOneOrFail()
|
||||
}
|
||||
|
||||
async getUsersIndiced(userIds: number[]): Promise<User[]> {
|
||||
if (!userIds.length) return []
|
||||
const users = await this.createQueryBuilder('user')
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
"change-password": "Fehler beim Ändern des Passworts",
|
||||
"error": "Fehler",
|
||||
"no-account": "Leider konnten wir keinen Account finden mit diesen Daten!",
|
||||
"no-email-verify": "Die Email wurde noch nicht bestätigt, bitte überprüfe deine Emails und klicke auf den Aktivierungslink!",
|
||||
"session-expired": "Sitzung abgelaufen!"
|
||||
},
|
||||
"form": {
|
||||
@ -180,9 +181,12 @@
|
||||
"uppercase": "Ein Großbuchstabe erforderlich."
|
||||
},
|
||||
"thx": {
|
||||
"activateEmail": "Deine Email wurde noch nicht aktiviert, bitte überprüfe deine Email und Klicke den Aktivierungslink!",
|
||||
"checkEmail": "Deine Email würde erfolgreich verifiziert.",
|
||||
"email": "Wir haben dir eine eMail gesendet.",
|
||||
"register": "Du bist jetzt registriert.",
|
||||
"emailActivated": "Danke dass Du deine Email bestätigt hast.",
|
||||
"errorTitle": "Achtung!",
|
||||
"register": "Du bist jetzt registriert, bitte überprüfe deine Emails und klicke auf den Aktivierungslink.",
|
||||
"reset": "Dein Passwort wurde geändert.",
|
||||
"title": "Danke!"
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
"change-password": "Error while changing password",
|
||||
"error": "Error",
|
||||
"no-account": "Unfortunately we could not find an account to the given data!",
|
||||
"no-email-verify": "Your email is not activated yet, please check your emails and click the activation link!",
|
||||
"session-expired": "The session expired"
|
||||
},
|
||||
"form": {
|
||||
@ -180,9 +181,12 @@
|
||||
"uppercase": "One uppercase letter required."
|
||||
},
|
||||
"thx": {
|
||||
"activateEmail": "Your email has not been activated yet, please check your emails and click the activation link!",
|
||||
"checkEmail": "Your email has been successfully verified.",
|
||||
"email": "We have sent you an email.",
|
||||
"register": "You are registred now.",
|
||||
"emailActivated": "Thank you your email has been activated.",
|
||||
"errorTitle": "Attention!",
|
||||
"register": "You are registered now, please check your emails and click the activation link.",
|
||||
"reset": "Your password has been changed.",
|
||||
"title": "Thank you!"
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ const routes = [
|
||||
path: '/thx/:comingFrom',
|
||||
component: () => import('../views/Pages/thx.vue'),
|
||||
beforeEnter: (to, from, next) => {
|
||||
const validFrom = ['password', 'reset', 'register']
|
||||
const validFrom = ['password', 'reset', 'register', 'login']
|
||||
if (!validFrom.includes(from.path.split('/')[1])) {
|
||||
next({ path: '/login' })
|
||||
} else {
|
||||
|
||||
@ -104,9 +104,14 @@ export default {
|
||||
this.$router.push('/overview')
|
||||
loader.hide()
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((error) => {
|
||||
if (!error.message.includes('user email not validated')) {
|
||||
this.$toasted.error(this.$t('error.no-account'))
|
||||
} else {
|
||||
// : this.$t('error.no-email-verify')
|
||||
this.$router.push('/thx/login')
|
||||
}
|
||||
loader.hide()
|
||||
this.$toasted.error(this.$t('error.no-account'))
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
@ -161,6 +161,7 @@ import InputEmail from '../../components/Inputs/InputEmail.vue'
|
||||
import InputPasswordConfirmation from '../../components/Inputs/InputPasswordConfirmation.vue'
|
||||
import LanguageSwitchSelect from '../../components/LanguageSwitchSelect.vue'
|
||||
import { registerUser } from '../../graphql/mutations'
|
||||
import { localeChanged } from 'vee-validate'
|
||||
import { getCommunityInfoMixin } from '../../mixins/getCommunityInfo'
|
||||
|
||||
export default {
|
||||
@ -189,6 +190,9 @@ export default {
|
||||
methods: {
|
||||
updateLanguage(e) {
|
||||
this.language = e
|
||||
this.$store.commit('language', this.language)
|
||||
this.$i18n.locale = this.language
|
||||
localeChanged(this.language)
|
||||
},
|
||||
getValidationState({ dirty, validated, valid = null }) {
|
||||
return dirty || validated ? valid : null
|
||||
|
||||
@ -4,10 +4,12 @@
|
||||
<div class="header py-7 py-lg-8 pt-lg-9">
|
||||
<b-container>
|
||||
<div class="header-body text-center mb-7">
|
||||
<p class="h1">{{ $t('site.thx.title') }}</p>
|
||||
<p class="h1">{{ $t(displaySetup.headline) }}</p>
|
||||
<p class="h4">{{ $t(displaySetup.subtitle) }}</p>
|
||||
<hr />
|
||||
<b-button :to="displaySetup.linkTo">{{ $t(displaySetup.button) }}</b-button>
|
||||
<b-button v-if="displaySetup.linkTo" :to="displaySetup.linkTo">
|
||||
{{ $t(displaySetup.button) }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-container>
|
||||
</div>
|
||||
@ -17,25 +19,33 @@
|
||||
<script>
|
||||
const textFields = {
|
||||
password: {
|
||||
headline: 'site.thx.title',
|
||||
subtitle: 'site.thx.email',
|
||||
button: 'login',
|
||||
linkTo: '/login',
|
||||
},
|
||||
reset: {
|
||||
headline: 'site.thx.title',
|
||||
subtitle: 'site.thx.reset',
|
||||
button: 'login',
|
||||
linkTo: '/login',
|
||||
},
|
||||
register: {
|
||||
headline: 'site.thx.title',
|
||||
subtitle: 'site.thx.register',
|
||||
button: 'site.login.signin',
|
||||
linkTo: '/overview',
|
||||
},
|
||||
checkEmail: {
|
||||
headline: 'site.thx.title',
|
||||
subtitle: 'site.thx.checkEmail',
|
||||
button: 'login',
|
||||
linkTo: '/login',
|
||||
},
|
||||
login: {
|
||||
headline: 'site.thx.errorTitle',
|
||||
subtitle: 'site.thx.activateEmail',
|
||||
},
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@ -147,7 +147,6 @@ Poco::JSON::Object* JsonUnsecureLogin::handle(Poco::Dynamic::Var params)
|
||||
infos.add("set user.group_id to default group_id = 1");
|
||||
case USER_NO_PRIVATE_KEY:
|
||||
case USER_COMPLETE:
|
||||
case USER_EMAIL_NOT_ACTIVATED:
|
||||
result->set("state", "success");
|
||||
result->set("user", session->getNewUser()->getJson());
|
||||
result->set("session_id", session->getHandle());
|
||||
@ -158,6 +157,10 @@ Poco::JSON::Object* JsonUnsecureLogin::handle(Poco::Dynamic::Var params)
|
||||
AWAIT(hasElopageTask)
|
||||
result->set("hasElopage", hasElopageTask->hasElopage());
|
||||
return result;
|
||||
case USER_EMAIL_NOT_ACTIVATED:
|
||||
result->set("state", "processing");
|
||||
result->set("msg", "user email not validated");
|
||||
break;
|
||||
default:
|
||||
result->set("state", "error");
|
||||
result->set("msg", "unknown user state");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user