New "about" section on PreferencesPage, add new exercise descriptions/steps

This commit is contained in:
2024-11-01 03:56:38 +01:00
parent 98e2a3c3db
commit 159b4434df
10 changed files with 209 additions and 75 deletions

View File

@@ -27,7 +27,32 @@
"nameDe": "SQL Injections", "nameDe": "SQL Injections",
"nameEn": "SQL Injections", "nameEn": "SQL Injections",
"groupNr": 1, "groupNr": 1,
"exercises": [] "exercises": [
{
"nameDe": "Accountnamen auslesen",
"nameEn": "Readout account names",
"exerciseNr": 1,
"descriptionDe": "Lasse dir alle Accountnamen über das Suchfeld ausgeben",
"descriptionEn": "Readout all account names via the search field",
"solved": false
},
{
"nameDe": "Passwort auslesen",
"nameEn": "Readout password",
"exerciseNr": 2,
"descriptionDe": "Versuche ein Passwort aus der Datenbank eines Accounts auszulesen",
"descriptionEn": "Get the password of an account from the database",
"solved": false
},
{
"nameDe": "Verändere deine Account Berechtigungen",
"nameEn": "Change your account role",
"exerciseNr": 3,
"descriptionDe": "Ändere die Berechtigungen deines Accounts",
"descriptionEn": "Change the privileges of your account",
"solved": false
}
]
}, },
{ {
"nameDe": "Broken Access Control", "nameDe": "Broken Access Control",
@@ -41,6 +66,14 @@
"descriptionDe": "Manipuliere die URL so, dass du das Admin-Panel erreichen kannst", "descriptionDe": "Manipuliere die URL so, dass du das Admin-Panel erreichen kannst",
"descriptionEn": "Manipulate the URL and access the admin panel", "descriptionEn": "Manipulate the URL and access the admin panel",
"solved": false "solved": false
},
{
"nameDe": "Das versteckte Konzert buchen",
"nameEn": "Book the hidden concert",
"exerciseNr": 2,
"descriptionDe": "Manipuliere die URL so, dass du das ausgebuchte Konzert aufrufen kannst und buche ein Ticket dafür",
"descriptionEn": "Manipulate the URL and access the sold out concert and buy a ticket",
"solved": false
} }
] ]
}, },
@@ -56,6 +89,22 @@
"descriptionDe": "Nimm dir eine URL des Shops und erweitere sie mit JavaScript Code so, dass beim Öffnen des Links eine 'Hallo Welt' Nachricht erscheint", "descriptionDe": "Nimm dir eine URL des Shops und erweitere sie mit JavaScript Code so, dass beim Öffnen des Links eine 'Hallo Welt' Nachricht erscheint",
"descriptionEn": "Take an URL of the shop and extend it with JavaScript code so that a 'Hello World' message appears whent the link is opened", "descriptionEn": "Take an URL of the shop and extend it with JavaScript code so that a 'Hello World' message appears whent the link is opened",
"solved": false "solved": false
},
{
"nameDe": "Ein externes Script aufrufen",
"nameEn": "Run an external script",
"exerciseNr": 2,
"descriptionDe": "Bearbeite die URL des Shops so, dass du das Script ausführen kannst",
"descriptionEn": "Create an URL of the shop, which calls the script",
"solved": false
},
{
"nameDe": "Hacken mit eigenem Script",
"nameEn": "Hack with your script",
"exerciseNr": 3,
"descriptionDe": "Schreibe eine JavaScript Datei, lade sie über das Admin Panel hoch und kreiere eine URL, welche es ausführt",
"descriptionEn": "Write our own JavaScript file, upload it via Admin Panel and create an URL to execute it",
"solved": false
} }
] ]
} }

View File

@@ -29,7 +29,7 @@ defineProps({
style="background-color: transparent" style="background-color: transparent"
> >
<div> <div>
<div class="pl-2 py-1"> <div class="pl-2 py-1 d-flex justify-center">
<v-icon :icon="icon" v-if="icon" />&nbsp;{{ title }} <v-icon :icon="icon" v-if="icon" />&nbsp;{{ title }}
</div> </div>
<div> <div>
@@ -40,9 +40,9 @@ defineProps({
</v-sheet> </v-sheet>
</v-card-title> </v-card-title>
<slot name="borderless"></slot> <slot name="borderless" v-if="$slots.borderless"></slot>
<v-container> <v-container v-if="$slots.default">
<v-row> <v-row>
<v-col> <v-col>
<slot></slot> <slot></slot>

View File

@@ -8,12 +8,12 @@ const showDialog: ModelRef<boolean> = defineModel()
const props = defineProps({ const props = defineProps({
title: String, title: String,
description: String, description: String,
onConfirm: Function onConfirm: Function,
loading: Boolean
}) })
function confirmPressed() { function confirmPressed() {
props.onConfirm() props.onConfirm()
showDialog.value = false
} }
</script> </script>
@@ -22,6 +22,7 @@ function confirmPressed() {
:title="title" :title="title"
max-width="400" max-width="400"
v-model="showDialog" v-model="showDialog"
persistent
> >
{{ description }} {{ description }}
@@ -30,6 +31,7 @@ function confirmPressed() {
@click="showDialog = false" @click="showDialog = false"
prepend-icon="mdi-close" prepend-icon="mdi-close"
color="orange" color="orange"
:loading="loading"
> >
{{ $t("misc.actions.cancel") }} {{ $t("misc.actions.cancel") }}
</outlined-button> </outlined-button>
@@ -38,6 +40,7 @@ function confirmPressed() {
@click="confirmPressed" @click="confirmPressed"
prepend-icon="mdi-check" prepend-icon="mdi-check"
color="red" color="red"
:loading="loading"
> >
{{ $t("misc.actions.confirm") }} {{ $t("misc.actions.confirm") }}
</outlined-button> </outlined-button>

View File

@@ -143,7 +143,8 @@
"title": "Übungsfortschritt zurücksetzen?", "title": "Übungsfortschritt zurücksetzen?",
"description": "Soll der Bearbeitungsfortschritt der Übungen wirklich zurückgesetzt werden? Dies kann nicht rückgänig gemacht werden!" "description": "Soll der Bearbeitungsfortschritt der Übungen wirklich zurückgesetzt werden? Dies kann nicht rückgänig gemacht werden!"
} }
} },
"aboutProject": "Über das Projekt"
}, },
"help": { "help": {
"scoreBoard": { "scoreBoard": {

View File

@@ -143,7 +143,8 @@
"title": "Reset exercise progress?", "title": "Reset exercise progress?",
"description": "Do you really want to reset the exercise progress? This is permanent!" "description": "Do you really want to reset the exercise progress? This is permanent!"
} }
} },
"aboutProject": "About the project"
}, },
"help": { "help": {
"scoreBoard": { "scoreBoard": {

View File

@@ -0,0 +1,42 @@
<script setup lang="ts">
import cardView from '@/components/basics/cardView.vue';
import packageJson from './../../../../package.json'
</script>
<template>
<card-view
:title="$t('preferences.aboutProject')"
icon="mdi-information"
>
<template #borderless>
<v-list>
<v-list-item
title="Software Version"
:subtitle="packageJson.version"
prepend-icon="mdi-counter"
/>
<v-list-item
title="Lizenz"
subtitle="MIT"
prepend-icon="mdi-license"
/>
<v-list-item
title="Entwickler"
subtitle="Tobias Zoghaib"
prepend-icon="mdi-account"
/>
<v-list-item
title="Entwickelt im Auftrag"
subtitle="Uni Hannover, Institut für IT-Sicherheit, Fachgebiet Usable Security and Privacy"
prepend-icon="mdi-school"
/>
<v-list-item
title="Copyright"
subtitle="2024"
prepend-icon="mdi-copyright"
/>
</v-list>
</template>
</card-view>
</template>

View File

@@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import pageSetup from './pageSetup.vue'; import pageSetup from './pageSetup.vue';
import systemSetup from './systemSetup.vue'; import systemSetup from './systemSetup.vue';
import aboutSection from './aboutSection.vue';
</script> </script>
<template> <template>
@@ -16,5 +17,11 @@ import systemSetup from './systemSetup.vue';
<system-setup /> <system-setup />
</v-col> </v-col>
</v-row> </v-row>
<v-row>
<v-col>
<about-section />
</v-col>
</v-row>
</v-container> </v-container>
</template> </template>

View File

@@ -30,6 +30,7 @@ function changeLanguage() {
:items="themeEnums" :items="themeEnums"
:label="$t('preferences.selectedTheme')" :label="$t('preferences.selectedTheme')"
@update:model-value="changeTheme" @update:model-value="changeTheme"
variant="outlined"
hide-details hide-details
/> />
</v-col> </v-col>
@@ -42,6 +43,7 @@ function changeLanguage() {
:items="$i18n.availableLocales" :items="$i18n.availableLocales"
:label="$t('preferences.language')" :label="$t('preferences.language')"
@update:model-value="changeLanguage" @update:model-value="changeLanguage"
variant="outlined"
hide-details hide-details
/> />
</v-col> </v-col>

View File

@@ -1,59 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import { useFeedbackStore } from '@/stores/feedback.store';
import cardView from '@/components/basics/cardView.vue'; import cardView from '@/components/basics/cardView.vue';
import outlinedButton from '@/components/basics/outlinedButton.vue'; import outlinedButton from '@/components/basics/outlinedButton.vue';
import { ref } from 'vue';
import confirmDialog from '@/components/basics/confirmDialog.vue'; import confirmDialog from '@/components/basics/confirmDialog.vue';
import { fetchServerState, resetDatabase, resetExerciseProgress } from '@/data/api/mainApi';
import { ServerStateEnum } from '@/data/enums/serverStateEnum'; import { ServerStateEnum } from '@/data/enums/serverStateEnum';
import packageJson from './../../../../package.json' import { usePreferencesStore } from '@/stores/preferences.store';
const feedbackStore = useFeedbackStore() const preferenceStore = usePreferencesStore()
const showConfirmDeleteDbDialog = ref(false)
const showConfirmDeleteExerciseProgressDialog = ref(false)
const serverOnline = ref(ServerStateEnum.PENDING)
fetchServerState()
.then(result => {
if (result.status == 200) {
serverOnline.value = ServerStateEnum.ONLINE
} else {
serverOnline.value = ServerStateEnum.OFFLINE
}
})
.catch(error => {
serverOnline.value = ServerStateEnum.OFFLINE
})
async function resetDb() {
serverOnline.value = ServerStateEnum.PENDING
await resetDatabase()
.then(result => {
if (result.status == 200) {
feedbackStore.changeBanner(BannerStateEnum.DATABASERESETSUCCESSFUL)
serverOnline.value = ServerStateEnum.ONLINE
}
showConfirmDeleteDbDialog.value = false
})
}
async function resetExerciseProg() {
serverOnline.value = ServerStateEnum.PENDING
await resetExerciseProgress()
.then(result => {
if (result.status == 200) {
feedbackStore.changeBanner(BannerStateEnum.EXERCISEPROGRESSRESETSUCCESSFUL)
serverOnline.value = ServerStateEnum.ONLINE
}
showConfirmDeleteExerciseProgressDialog.value = false
})
}
preferenceStore.getServerState()
</script> </script>
<template> <template>
@@ -64,36 +18,32 @@ async function resetExerciseProg() {
<v-row> <v-row>
<v-col> <v-col>
{{ $t('preferences.serverState') }}: {{ $t('preferences.serverState') }}:
<span v-if="serverOnline == ServerStateEnum.ONLINE" class="text-green"> <span v-if="preferenceStore.serverState == ServerStateEnum.ONLINE" class="text-green">
<v-icon icon="mdi-check" /> <v-icon icon="mdi-check" />
Online Online
</span> </span>
<span v-else-if="serverOnline == ServerStateEnum.OFFLINE" class="text-red"> <span v-else-if="preferenceStore.serverState == ServerStateEnum.OFFLINE" class="text-red">
<v-icon icon="mdi-alert-circle" /> <v-icon icon="mdi-alert-circle" />
Offline Offline
</span> </span>
<span v-else-if="serverOnline == ServerStateEnum.PENDING" class="text-orange"> <span v-else-if="preferenceStore.serverState == ServerStateEnum.PENDING" class="text-orange">
<v-icon icon="mdi-clock" /> <v-icon icon="mdi-clock" />
Pending... Pending...
</span> </span>
</v-col> </v-col>
</v-row> </v-row>
<v-row>
<v-col>
Software Version: {{ packageJson.version }}
</v-col>
</v-row>
<v-row> <v-row>
<v-col class="d-flex justify-center align-center"> <v-col class="d-flex justify-center align-center">
<outlined-button <outlined-button
@click="showConfirmDeleteDbDialog = true" @click="preferenceStore.showDeleteDbDialog = true"
prepend-icon="mdi-database-refresh" prepend-icon="mdi-database-refresh"
color="red" color="red"
:disabled="serverOnline != ServerStateEnum.ONLINE" :disabled="preferenceStore.serverState != ServerStateEnum.ONLINE"
> >
{{ $t('preferences.resetDatabase.resetDatabase') }} {{ $t('preferences.resetDatabase.resetDatabase') }}
</outlined-button> </outlined-button>
@@ -103,10 +53,10 @@ async function resetExerciseProg() {
<v-row> <v-row>
<v-col class="d-flex justify-center align-center"> <v-col class="d-flex justify-center align-center">
<outlined-button <outlined-button
@click="showConfirmDeleteExerciseProgressDialog = true" @click="preferenceStore.showDeleteExerciseDialog = true"
prepend-icon="mdi-progress-close" prepend-icon="mdi-progress-close"
color="red" color="red"
:disabled="serverOnline != ServerStateEnum.ONLINE" :disabled="preferenceStore.serverState != ServerStateEnum.ONLINE"
> >
{{ $t('preferences.resetExerciseProgress.resetExerciseProgress') }} {{ $t('preferences.resetExerciseProgress.resetExerciseProgress') }}
</outlined-button> </outlined-button>
@@ -118,15 +68,17 @@ async function resetExerciseProg() {
<confirm-dialog <confirm-dialog
:title="$t('preferences.resetDatabase.dialog.title')" :title="$t('preferences.resetDatabase.dialog.title')"
:description="$t('preferences.resetDatabase.dialog.description')" :description="$t('preferences.resetDatabase.dialog.description')"
v-model="showConfirmDeleteDbDialog" v-model="preferenceStore.showDeleteDbDialog"
:onConfirm="resetDb" :onConfirm="preferenceStore.resetDb"
:loading="preferenceStore.fetchInProgress"
/> />
<!-- Confirm delete exercise progress --> <!-- Confirm delete exercise progress -->
<confirm-dialog <confirm-dialog
:title="$t('preferences.resetExerciseProgress.dialog.title')" :title="$t('preferences.resetExerciseProgress.dialog.title')"
:description="$t('preferences.resetExerciseProgress.dialog.description')" :description="$t('preferences.resetExerciseProgress.dialog.description')"
v-model="showConfirmDeleteExerciseProgressDialog" v-model="preferenceStore.showDeleteExerciseDialog"
:onConfirm="resetExerciseProg" :onConfirm="preferenceStore.resetExerciseProg"
:loading="preferenceStore.fetchInProgress"
/> />
</template> </template>

View File

@@ -3,6 +3,10 @@ import { useLocalStorage } from "@vueuse/core";
import { ThemeEnum } from "../data/enums/themeEnums"; import { ThemeEnum } from "../data/enums/themeEnums";
import { LanguageEnum } from "../data/enums/languageEnum"; import { LanguageEnum } from "../data/enums/languageEnum";
import { ref } from "vue"; import { ref } from "vue";
import { fetchServerState, resetDatabase, resetExerciseProgress } from "@/data/api/mainApi";
import { ServerStateEnum } from "@/data/enums/serverStateEnum";
import { BannerStateEnum } from "@/data/enums/bannerStateEnum";
import { useFeedbackStore } from "./feedback.store";
export const usePreferencesStore = defineStore('preferencesStore', { export const usePreferencesStore = defineStore('preferencesStore', {
state: () => ({ state: () => ({
@@ -13,6 +17,79 @@ export const usePreferencesStore = defineStore('preferencesStore', {
language: useLocalStorage<LanguageEnum>("hackmycart/preferencesStore/language", LanguageEnum.GERMAN), language: useLocalStorage<LanguageEnum>("hackmycart/preferencesStore/language", LanguageEnum.GERMAN),
/** Request to server sent, waiting for data response */ /** Request to server sent, waiting for data response */
fetchInProgress: ref(false) fetchInProgress: ref(false),
/** State of the server */
serverState: ref<ServerStateEnum>(ServerStateEnum.PENDING),
/** Show the "Delete DB?" confirm dialog */
showDeleteDbDialog: ref(false),
/** Show the "Delete Exercise progress?" confirm dialog */
showDeleteExerciseDialog: ref(false)
}), }),
actions: {
/**
* Request the state of the backend server
*/
async getServerState() {
this.fetchInProgress = true
fetchServerState()
.then(result => {
if (result.status == 200) {
this.serverState = ServerStateEnum.ONLINE
} else {
this.serverState = ServerStateEnum.OFFLINE
}
this.fetchInProgress = false
})
.catch(error => {
this.serverState = ServerStateEnum.OFFLINE
this.fetchInProgress = false
})
},
/**
* Resets the database (without exercise tables)
*/
async resetDb() {
const feedbackStore = useFeedbackStore()
this.serverState = ServerStateEnum.PENDING
this.fetchInProgress = true
await resetDatabase()
.then(result => {
if (result.status == 200) {
feedbackStore.changeBanner(BannerStateEnum.DATABASERESETSUCCESSFUL)
this.serverState = ServerStateEnum.ONLINE
}
this.fetchInProgress = false
this.showDeleteDbDialog = false
})
},
/**
* Resets the exercise progress
*/
async resetExerciseProg() {
const feedbackStore = useFeedbackStore()
this.serverState = ServerStateEnum.PENDING
this.fetchInProgress = true
await resetExerciseProgress()
.then(result => {
if (result.status == 200) {
feedbackStore.changeBanner(BannerStateEnum.EXERCISEPROGRESSRESETSUCCESSFUL)
this.serverState = ServerStateEnum.ONLINE
}
this.fetchInProgress = false
this.showDeleteExerciseDialog = false
})
}
}
}) })