Merge remote-tracking branch 'origin/master' into 3505-feature-introduce-encrypted-jwts-in-backend-federation-communication

This commit is contained in:
clauspeterhuebner 2025-07-15 23:09:51 +02:00
commit 247038741c
23 changed files with 108 additions and 53 deletions

View File

@ -174,6 +174,13 @@ turbo frontend#dev backend#start admin#start --env-mode=loose
Tip: for local setup use a local nginx server with similar config like docker nginx [nginx.conf](./nginx/gradido.conf) but replace docker image name with localhost
### Clear
In root folder calling `yarn clear` will clear all turbo caches, node_modules and build folders of all workspaces for a clean rebuild.
```bash
yarn clear
```
## Services defined in this package

View File

@ -19,7 +19,8 @@
"test:debug": "cross-env TZ=UTC node --inspect-brk ./node_modules/vitest/vitest.mjs",
"test:watch": "cross-env TZ=UTC vitest",
"locales": "scripts/sort.sh",
"locales:fix": "scripts/sort.sh --fix"
"locales:fix": "scripts/sort.sh --fix",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"dependencies": {
"@iconify/json": "^2.2.228",

View File

@ -22,7 +22,8 @@
"locales": "scripts/sort.sh",
"locales:fix": "scripts/sort.sh --fix",
"start": "cross-env TZ=UTC node build/index.js",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"nodemonConfig": {
"ignore": [

View File

@ -21,7 +21,8 @@
"test": "bun test",
"test:debug": "bun test --inspect-brk",
"lint": "biome check --error-on-warnings .",
"lint:fix": "biome check --error-on-warnings . --write"
"lint:fix": "biome check --error-on-warnings . --write",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"devDependencies": {
"@biomejs/biome": "2.0.0",

View File

@ -21,7 +21,8 @@
"test:debug": "bun test --inspect-brk",
"typecheck": "tsc --noEmit",
"lint": "biome check --error-on-warnings .",
"lint:fix": "biome check --error-on-warnings . --write"
"lint:fix": "biome check --error-on-warnings . --write",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"devDependencies": {
"@biomejs/biome": "2.0.0",

View File

@ -19,7 +19,7 @@
"typecheck": "tsc --noEmit",
"lint": "biome check --error-on-warnings .",
"lint:fix": "biome check --error-on-warnings . --write",
"clear": "cross-env TZ=UTC tsx migration/index.ts clear",
"clearDB": "cross-env TZ=UTC tsx migration/index.ts clear",
"test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test vitest --reporter verbose --no-file-parallelism run",
"test:debug": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test node --inspect-brk node_modules/.bin/jest --bail --runInBand --forceExit --detectOpenHandles",
"up": "cross-env TZ=UTC tsx migration/index.ts up",
@ -28,7 +28,8 @@
"up:test": "cross-env TZ=UTC DB_DATABASE=gradido_test tsx migration/index.ts up",
"up:backend_test": "cross-env TZ=UTC DB_DATABASE=gradido_test_backend tsx migration/index.ts up",
"up:federation_test": "cross-env TZ=UTC DB_DATABASE=gradido_test_federation tsx migration/index.ts up",
"up:dht_test": "cross-env TZ=UTC DB_DATABASE=gradido_test_dht tsx migration/index.ts up"
"up:dht_test": "cross-env TZ=UTC DB_DATABASE=gradido_test_dht tsx migration/index.ts up",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"devDependencies": {
"@biomejs/biome": "2.0.0",

View File

@ -17,7 +17,8 @@
"lint:fix": "biome check --error-on-warnings . --write",
"test": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_dht jest --verbose --runInBand --forceExit --detectOpenHandles",
"test:debug": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_dht node --inspect-brk node_modules/.bin/jest --bail --runInBand --forceExit --detectOpenHandles",
"test:coverage": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_dht jest --coverage --runInBand --forceExit --detectOpenHandles"
"test:coverage": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_dht jest --coverage --runInBand --forceExit --detectOpenHandles",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"dependencies": {
"cross-env": "^7.0.3",

View File

@ -18,7 +18,8 @@
"test:debug": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_federation node --inspect-brk node_modules/.bin/jest --bail --runInBand --forceExit --detectOpenHandles",
"test:coverage": "cross-env TZ=UTC NODE_ENV=development DB_DATABASE=gradido_test_federation jest --coverage --runInBand --forceExit --detectOpenHandles",
"lint": "biome check --error-on-warnings .",
"lint:fix": "biome check --error-on-warnings . --write"
"lint:fix": "biome check --error-on-warnings . --write",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"dependencies": {
"cross-env": "^7.0.3",

View File

@ -21,7 +21,8 @@
"compile-scss": "node ./scripts/scss.mjs compile",
"watch-scss": "node ./scripts/scss.mjs watch",
"compile-scss-sass": "node ./scripts/scss.mjs compile sass",
"watch-scss-sass": "node ./scripts/scss.mjs watch sass"
"watch-scss-sass": "node ./scripts/scss.mjs watch sass",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"dependencies": {
"@morev/vue-transitions": "^3.0.2",

View File

@ -8,11 +8,11 @@
<BImg class="sheet-img position-absolute d-block d-lg-none zindex1000" :src="sheet"></BImg>
<BCollapse id="nav-collapse" is-nav>
<BNavbarNav class="ms-auto me-4 d-none d-lg-flex" right>
<NavItem :to="register()" class="auth-navbar ms-lg-5">
<NavItem :to="routeWithParamsAndQuery('Register')" class="auth-navbar ms-lg-5">
{{ $t('signup') }}
</NavItem>
<span class="d-none d-lg-block py-1">{{ $t('|') }}</span>
<NavItem :to="login()" class="auth-navbar">
<NavItem :to="routeWithParamsAndQuery('Login')" class="auth-navbar">
{{ $t('signin') }}
</NavItem>
</BNavbarNav>
@ -25,7 +25,7 @@
import { useAuthLinks } from '@/composables/useAuthLinks'
import NavItem from '../Menu/NavItem.vue'
const { login, register } = useAuthLinks()
const { routeWithParamsAndQuery } = useAuthLinks()
const backgroundHeader = '/img/template/gradido_background_header.png'
const logo = '/img/brand/gradido-logo_200x59.png'

View File

@ -2,9 +2,13 @@
<div class="navbar-small">
<BNavbar class="navi">
<BNavbarNav>
<NavItem :to="register()" class="auth-navbar">{{ $t('signup') }}</NavItem>
<NavItem :to="routeWithParamsAndQuery('Register')" class="auth-navbar">
{{ $t('signup') }}
</NavItem>
<span class="mt-1">{{ $t('|') }}</span>
<NavItem :to="login()" class="auth-navbar">{{ $t('signin') }}</NavItem>
<NavItem :to="routeWithParamsAndQuery('Login')" class="auth-navbar">
{{ $t('signin') }}
</NavItem>
</BNavbarNav>
</BNavbar>
</div>
@ -14,7 +18,7 @@
import { useAuthLinks } from '@/composables/useAuthLinks'
import NavItem from '../Menu/NavItem.vue'
const { login, register } = useAuthLinks()
const { routeWithParamsAndQuery } = useAuthLinks()
</script>
<style scoped>
.navi {

View File

@ -10,13 +10,15 @@
<BRow>
<BCol sm="12" md="6">
<p>{{ $t('gdd_per_link.no-account') }}</p>
<BButton variant="primary" :to="register()">
<BButton variant="primary" :to="routeWithParamsAndQuery('Register')">
{{ $t('gdd_per_link.to-register') }}
</BButton>
</BCol>
<BCol sm="12" md="6" class="mt-4 mt-lg-0">
<p>{{ $t('gdd_per_link.has-account') }}</p>
<BButton variant="gradido" :to="login()">{{ $t('gdd_per_link.to-login') }}</BButton>
<BButton variant="gradido" :to="routeWithParamsAndQuery('Login')">
{{ $t('gdd_per_link.to-login') }}
</BButton>
</BCol>
</BRow>
</BCard>
@ -26,7 +28,7 @@
<script setup>
import { useAuthLinks } from '@/composables/useAuthLinks'
const { login, register } = useAuthLinks()
const { routeWithParamsAndQuery } = useAuthLinks()
defineProps({
linkData: { type: Object, required: true },
isContributionLink: { type: Boolean, default: false },

View File

@ -17,13 +17,21 @@
<BRow>
<BCol sm="12" md="6">
<p>{{ $t('gdd_per_link.no-account') }}</p>
<BButton variant="primary" :disabled="isForeignCommunitySelected" :to="register()">
<BButton
variant="primary"
:disabled="isForeignCommunitySelected"
:to="routeWithParamsAndQuery('Register')"
>
{{ $t('gdd_per_link.to-register') }}
</BButton>
</BCol>
<BCol sm="12" md="6" class="mt-4 mt-lg-0">
<p>{{ $t('gdd_per_link.has-account') }}</p>
<BButton variant="gradido" :disabled="isForeignCommunitySelected" :to="login()">
<BButton
variant="gradido"
:disabled="isForeignCommunitySelected"
:to="routeWithParamsAndQuery('Login')"
>
{{ $t('gdd_per_link.to-login') }}
</BButton>
</BCol>
@ -37,7 +45,7 @@ import { ref, computed } from 'vue'
import CONFIG from '@/config'
import { useAuthLinks } from '@/composables/useAuthLinks'
const { login, register } = useAuthLinks()
const { routeWithParamsAndQuery } = useAuthLinks()
const props = defineProps({
linkData: { type: Object, required: true },
redeemCode: { type: String, required: true },

View File

@ -3,7 +3,7 @@
<span v-if="isActive" class="nav-link active" aria-current="page">
<slot></slot>
</span>
<BNavItem v-else :to="href" class="auth-navbar"><slot></slot></BNavItem>
<BNavItem v-else v-bind="props" class="auth-navbar"><slot></slot></BNavItem>
</li>
</template>

View File

@ -1,19 +1,20 @@
import { useRoute } from 'vue-router'
export function useAuthLinks() {
const { params } = useRoute()
const login = () => {
if (params.code) return '/login/' + params.code
return '/login'
}
const register = () => {
if (params.code) return '/register/' + params.code
return '/register'
const route = useRoute()
/**
* Combine current route params and query with given params and query
* @param {string} name
* @param {{ params: {}, query: {} }} options
* @returns {{ name: string, params: {}, query: {} }} a vue3 routing object for :to
*/
const routeWithParamsAndQuery = (name, options = { params: {}, query: {} }) => {
return {
name,
params: { ...route.params, ...options.params },
query: { ...route.query, ...options.query },
}
}
return {
login,
register,
}
return { routeWithParamsAndQuery }
}

View File

@ -13,7 +13,10 @@
</BRow>
<BRow>
<BCol class="d-flex justify-content-end mb-4 mb-lg-0">
<router-link to="/forgot-password" data-test="forgot-password-link">
<router-link
:to="routeWithParamsAndQuery('ForgotPassword')"
data-test="forgot-password-link"
>
{{ $t('settings.password.forgot_pwd') }}
</router-link>
</BCol>
@ -39,7 +42,7 @@
</BRow>
<BRow>
<BCol class="mt-1 auth-navbar">
<BLink :to="register()">
<BLink :to="routeWithParamsAndQuery('Register')">
{{ $t('signup') }}
</BLink>
</BCol>
@ -82,7 +85,7 @@ const { mutate } = useMutation(login)
const { mutate: mutateHumhubAutoLogin } = useMutation(authenticateHumhubAutoLoginProject)
// const $loading = useLoading() // TODO needs to be updated but there is some sort of an issue that breaks the app.
const { toastError } = useAppToast()
const { register } = useAuthLinks()
const { routeWithParamsAndQuery } = useAuthLinks()
const form = ref({
email: '',
@ -123,7 +126,7 @@ const onSubmit = handleSubmit(async (values) => {
}
if (route.params.code) {
await router.push(`/redeem/${route.params.code}`)
await router.push(routeWithParamsAndQuery('Redeem'))
} else {
await router.push(store.state.redirectPath)
}
@ -131,12 +134,12 @@ const onSubmit = handleSubmit(async (values) => {
if (error.message.includes('User email not validated')) {
showPageMessage.value = true
errorSubtitle.value = t('message.activateEmail')
errorLinkTo.value = '/forgot-password'
errorLinkTo.value = routeWithParamsAndQuery('ForgotPassword')
toastError(t('error.no-account'))
} else if (error.message.includes('User has no password set yet')) {
showPageMessage.value = true
errorSubtitle.value = t('message.unsetPassword')
errorLinkTo.value = '/reset-password/login'
errorLinkTo.value = routeWithParamsAndQuery('ResetPassword')
toastError(t('error.no-account'))
} else if (error.message.includes('No user with this credentials')) {
toastError(t('error.no-user'))

View File

@ -77,7 +77,7 @@
</BRow>
<BRow>
<BCol class="mt-1 auth-navbar">
<BLink :to="login()">
<BLink :to="routeWithParamsAndQuery('Login')">
{{ $t('signin') }}
</BLink>
</BCol>
@ -105,7 +105,7 @@ import { useAuthLinks } from '@/composables/useAuthLinks'
import CONFIG from '@/config'
const { toastError } = useAppToast()
const { login } = useAuthLinks()
const { routeWithParamsAndQuery } = useAuthLinks()
const { mutate } = useMutation(createUser)

View File

@ -417,7 +417,10 @@ describe('ResetPassword', () => {
'...email was sent more than 23 hours and 10 minutes ago',
)
expect(message.props('buttonText')).toBe('settings.password.reset')
expect(message.props('linkTo')).toBe('/forgot-password/resetPassword')
expect(message.props('linkTo')).toMatchObject({
name: 'ForgotPassword',
params: { comingFrom: 'reset-password' },
})
expect(mockToastError).toHaveBeenCalledWith(
'...email was sent more than 23 hours and 10 minutes ago',
)
@ -435,7 +438,7 @@ describe('ResetPassword', () => {
expect(message.props('headline')).toBe('message.title')
expect(message.props('subtitle')).toBe('message.checkEmail')
expect(message.props('buttonText')).toBe('login')
expect(message.props('linkTo')).toBe('/login')
expect(message.props('linkTo')).toMatchObject({ name: 'Login' })
})
it('handles success response on /reset-password', async () => {
@ -454,7 +457,7 @@ describe('ResetPassword', () => {
expect(message.props('headline')).toBe('message.title')
expect(message.props('subtitle')).toBe('message.checkEmail')
expect(message.props('buttonText')).toBe('login')
expect(message.props('linkTo')).toBe('/login')
expect(message.props('linkTo')).toMatchObject({ name: 'Login' })
})
})

View File

@ -41,19 +41,22 @@ import InputPasswordConfirmation from '@/components/Inputs/InputPasswordConfirma
import Message from '@/components/Message/Message.vue'
import { useAppToast } from '@/composables/useToast'
import { useForm } from 'vee-validate'
import { useAuthLinks } from '@/composables/useAuthLinks'
const { routeWithParamsAndQuery } = useAuthLinks()
const textFields = {
reset: {
title: 'settings.password.change-password',
text: 'settings.password.reset-password.text',
button: 'settings.password.change-password',
linkTo: '/login',
linkTo: routeWithParamsAndQuery('Login'),
},
checkEmail: {
title: 'settings.password.set',
text: 'settings.password.set-password.text',
button: 'settings.password.set',
linkTo: '/login',
linkTo: routeWithParamsAndQuery('Login'),
},
}
@ -100,7 +103,7 @@ const onSubmit = async () => {
? t('message.checkEmail')
: t('message.reset')
messageButtonText.value = t('login')
messageButtonLinkTo.value = route.params.code ? `/login/${route.params.code}` : '/login'
messageButtonLinkTo.value = routeWithParamsAndQuery('Login')
} catch (error) {
const errorMessage = error.message.match(
/email was sent more than ([0-9]+ hours)?( and )?([0-9]+ minutes)? ago/,
@ -112,7 +115,9 @@ const onSubmit = async () => {
messageHeadline.value = t('message.errorTitle')
messageSubtitle.value = errorMessage
messageButtonText.value = t('settings.password.reset')
messageButtonLinkTo.value = '/forgot-password/resetPassword'
messageButtonLinkTo.value = routeWithParamsAndQuery('ForgotPassword', {
params: { comingFrom: 'reset-password' },
})
toastError(errorMessage)
}
}
@ -124,7 +129,9 @@ const checkOptInCode = async () => {
})
} catch (error) {
toastError(error.message)
await router.push('/forgot-password/resetPassword')
await router.push(
routeWithParamsAndQuery('ForgotPassword', { params: { comingFrom: 'reset-password' } }),
)
}
}

View File

@ -114,18 +114,22 @@ const routes = [
},
},
{
name: 'Login',
path: '/login/:code?',
component: () => import('@/pages/Login'),
},
{
name: 'Register',
path: '/register/:code?',
component: () => import('@/pages/Register'),
},
{
name: 'ForgotPassword',
path: '/forgot-password',
component: () => import('@/pages/ForgotPassword'),
},
{
name: 'ForgotPasswordComingFrom',
path: '/forgot-password/:comingFrom',
component: () => import('@/pages/ForgotPassword'),
},
@ -138,14 +142,17 @@ const routes = [
// component: () => import('@/pages/SelectCommunity'),
// },
{
name: 'ResetPassword',
path: '/reset-password/:optin',
component: () => import('@/pages/ResetPassword'),
},
{
name: 'CheckEmail',
path: '/checkEmail/:optin/:code?',
component: () => import('@/pages/ResetPassword'),
},
{
name: 'Redeem',
path: '/redeem/:code',
component: () => import('@/pages/TransactionLink'),
},

View File

@ -25,7 +25,8 @@
"docker": "cross-env BUILD_COMMIT=$(git rev-parse HEAD) docker compose -f docker-compose.yml up",
"docker:rebuild": "cross-env BUILD_COMMIT=$(git rev-parse HEAD) docker compose -f docker-compose.yml build",
"docker_dev": "cross-env BUILD_COMMIT=$(git rev-parse HEAD) docker compose up",
"docker_dev:rebuild": "cross-env BUILD_COMMIT=$(git rev-parse HEAD) docker compose build"
"docker_dev:rebuild": "cross-env BUILD_COMMIT=$(git rev-parse HEAD) docker compose build",
"clear": "rm -rf .turbo && turbo clear"
},
"dependencies": {
"auto-changelog": "^2.4.0",

View File

@ -21,7 +21,8 @@
"test:debug": "bun test --inspect-brk",
"typecheck": "tsc --noEmit",
"lint": "biome check --error-on-warnings .",
"lint:fix": "biome check --error-on-warnings . --write"
"lint:fix": "biome check --error-on-warnings . --write",
"clear": "rm -rf node_modules && rm -rf build && rm -rf .turbo"
},
"devDependencies": {
"@biomejs/biome": "2.0.0",

View File

@ -24,6 +24,9 @@
"dependsOn": ["build"],
"persistent": true,
"cache": false
},
"clear": {
"cache": false
}
}
}