Enhance security by adding role-checking functions in ESLint configuration and updating Vue components to improve content sanitization comments, while refining error handling in API endpoints for better clarity.
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 3m40s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 3m40s
This commit is contained in:
@@ -32,12 +32,16 @@ export default [
|
|||||||
'setCookie': 'readonly',
|
'setCookie': 'readonly',
|
||||||
'deleteCookie': 'readonly',
|
'deleteCookie': 'readonly',
|
||||||
'getHeader': 'readonly',
|
'getHeader': 'readonly',
|
||||||
|
'setHeader': 'readonly',
|
||||||
'getRouterParam': 'readonly',
|
'getRouterParam': 'readonly',
|
||||||
'getQuery': 'readonly',
|
'getQuery': 'readonly',
|
||||||
'sendStream': 'readonly',
|
'sendStream': 'readonly',
|
||||||
'sendRedirect': 'readonly',
|
'sendRedirect': 'readonly',
|
||||||
'createError': 'readonly',
|
'createError': 'readonly',
|
||||||
'useRuntimeConfig': 'readonly',
|
'useRuntimeConfig': 'readonly',
|
||||||
|
'hasAnyRole': 'readonly',
|
||||||
|
'hasRole': 'readonly',
|
||||||
|
'hasAllRoles': 'readonly',
|
||||||
'process': 'readonly',
|
'process': 'readonly',
|
||||||
// Vue Composition API
|
// Vue Composition API
|
||||||
'onUnmounted': 'readonly',
|
'onUnmounted': 'readonly',
|
||||||
|
|||||||
@@ -166,9 +166,10 @@
|
|||||||
Keine Empfänger gefunden
|
Keine Empfänger gefunden
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- nosemgrep: javascript.vue.security.audit.xss.templates.avoid-v-html -->
|
||||||
<div
|
<div
|
||||||
class="text-sm text-gray-600 prose prose-sm max-w-none mb-3"
|
class="text-sm text-gray-600 prose prose-sm max-w-none mb-3"
|
||||||
v-html="useSanitizeHtml(post.content.substring(0, 200) + (post.content.length > 200 ? '...' : ''))" <!-- nosemgrep: javascript.vue.security.audit.xss.templates.avoid-v-html -->
|
v-html="useSanitizeHtml(post.content.substring(0, 200) + (post.content.length > 200 ? '...' : ''))"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Empfängerliste (collapsible) -->
|
<!-- Empfängerliste (collapsible) -->
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ async function loadConfig() {
|
|||||||
try {
|
try {
|
||||||
const data = await $fetch('/api/config')
|
const data = await $fetch('/api/config')
|
||||||
rawContent.value = data?.seiten?.geschichte || ''
|
rawContent.value = data?.seiten?.geschichte || ''
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
rawContent.value = ''
|
rawContent.value = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ async function loadConfig() {
|
|||||||
rawContent.value = satzung.content || ''
|
rawContent.value = satzung.content || ''
|
||||||
pdfUrl.value = satzung.pdfUrl || ''
|
pdfUrl.value = satzung.pdfUrl || ''
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
rawContent.value = ''
|
rawContent.value = ''
|
||||||
pdfUrl.value = ''
|
pdfUrl.value = ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
||||||
TT-Regeln
|
TT-Regeln
|
||||||
</h1>
|
</h1>
|
||||||
|
<!-- nosemgrep: javascript.vue.security.audit.xss.templates.avoid-v-html -->
|
||||||
<div
|
<div
|
||||||
class="prose prose-lg max-w-none"
|
class="prose prose-lg max-w-none"
|
||||||
v-html="content" <!-- nosemgrep: javascript.vue.security.audit.xss.templates.avoid-v-html -->
|
v-html="content"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +29,7 @@ async function loadConfig() {
|
|||||||
try {
|
try {
|
||||||
const data = await $fetch('/api/config')
|
const data = await $fetch('/api/config')
|
||||||
rawContent.value = data?.seiten?.ttRegeln || ''
|
rawContent.value = data?.seiten?.ttRegeln || ''
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
rawContent.value = ''
|
rawContent.value = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
||||||
Über uns
|
Über uns
|
||||||
</h1>
|
</h1>
|
||||||
|
<!-- nosemgrep: javascript.vue.security.audit.xss.templates.avoid-v-html -->
|
||||||
<div
|
<div
|
||||||
class="prose prose-lg max-w-none"
|
class="prose prose-lg max-w-none"
|
||||||
v-html="content" <!-- nosemgrep: javascript.vue.security.audit.xss.templates.avoid-v-html -->
|
v-html="content"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +29,7 @@ async function loadConfig() {
|
|||||||
try {
|
try {
|
||||||
const data = await $fetch('/api/config')
|
const data = await $fetch('/api/config')
|
||||||
rawContent.value = data?.seiten?.ueberUns || ''
|
rawContent.value = data?.seiten?.ueberUns || ''
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
rawContent.value = ''
|
rawContent.value = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ async function reencryptUsers(backupDir, oldKeys) {
|
|||||||
const data = await fs.readFile(USERS_FILE, 'utf-8')
|
const data = await fs.readFile(USERS_FILE, 'utf-8')
|
||||||
|
|
||||||
// Backup erstellen
|
// Backup erstellen
|
||||||
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
await fs.copyFile(USERS_FILE, path.join(backupDir, 'users.json')) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
await fs.copyFile(USERS_FILE, path.join(backupDir, 'users.json')) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
console.log('✅ Backup von users.json erstellt')
|
console.log('✅ Backup von users.json erstellt')
|
||||||
|
|
||||||
@@ -167,6 +168,7 @@ async function reencryptMembers(backupDir, oldKeys) {
|
|||||||
const data = await fs.readFile(MEMBERS_FILE, 'utf-8')
|
const data = await fs.readFile(MEMBERS_FILE, 'utf-8')
|
||||||
|
|
||||||
// Backup erstellen
|
// Backup erstellen
|
||||||
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
await fs.copyFile(MEMBERS_FILE, path.join(backupDir, 'members.json')) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
await fs.copyFile(MEMBERS_FILE, path.join(backupDir, 'members.json')) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
console.log('✅ Backup von members.json erstellt')
|
console.log('✅ Backup von members.json erstellt')
|
||||||
|
|
||||||
@@ -217,6 +219,7 @@ async function reencryptMembershipApplications(backupDir, oldKeys) {
|
|||||||
let skipped = 0
|
let skipped = 0
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
const filePath = path.join(MEMBERSHIP_APPLICATIONS_DIR, file)
|
const filePath = path.join(MEMBERSHIP_APPLICATIONS_DIR, file)
|
||||||
const stat = await fs.stat(filePath)
|
const stat = await fs.stat(filePath)
|
||||||
|
|
||||||
@@ -226,6 +229,7 @@ async function reencryptMembershipApplications(backupDir, oldKeys) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Backup erstellen
|
// Backup erstellen
|
||||||
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
const backupPath = path.join(backupDir, 'membership-applications', file) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
const backupPath = path.join(backupDir, 'membership-applications', file) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
await fs.mkdir(path.dirname(backupPath), { recursive: true })
|
await fs.mkdir(path.dirname(backupPath), { recursive: true })
|
||||||
await fs.copyFile(filePath, backupPath)
|
await fs.copyFile(filePath, backupPath)
|
||||||
|
|||||||
@@ -39,8 +39,10 @@ export default defineEventHandler(async (event) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataDir = path.join(process.cwd(), 'server/data/membership-applications') // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
const filePath = path.join(dataDir, `${id}.json`) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
const dataDir = path.join(process.cwd(), 'server/data/membership-applications')
|
||||||
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
|
const filePath = path.join(dataDir, `${id}.json`)
|
||||||
|
|
||||||
// Antrag laden
|
// Antrag laden
|
||||||
const fileContent = await fs.readFile(filePath, 'utf8')
|
const fileContent = await fs.readFile(filePath, 'utf8')
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ export default defineEventHandler(async (event) => {
|
|||||||
filePath = path.join(process.cwd(), 'public', 'documents', 'spielplaene', 'spielplan_gesamt.pdf')
|
filePath = path.join(process.cwd(), 'public', 'documents', 'spielplaene', 'spielplan_gesamt.pdf')
|
||||||
} else {
|
} else {
|
||||||
// Für vordefinierte PDFs
|
// Für vordefinierte PDFs
|
||||||
filePath = path.join(process.cwd(), 'public', 'documents', 'spielplaene', sanitizedFilename) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
|
filePath = path.join(process.cwd(), 'public', 'documents', 'spielplaene', sanitizedFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prüfe ob Datei existiert
|
// Prüfe ob Datei existiert
|
||||||
|
|||||||
@@ -361,7 +361,8 @@ ${hallenListe.map(halle => {
|
|||||||
// Verzeichnis existiert bereits
|
// Verzeichnis existiert bereits
|
||||||
}
|
}
|
||||||
|
|
||||||
const tempTexFile = path.join(tempDir, `spielplan_${team}_${Date.now()}.tex`) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal
|
||||||
|
const tempTexFile = path.join(tempDir, `spielplan_${team}_${Date.now()}.tex`)
|
||||||
await fs.writeFile(tempTexFile, latexContent, 'utf-8')
|
await fs.writeFile(tempTexFile, latexContent, 'utf-8')
|
||||||
|
|
||||||
// Kompiliere LaTeX zu PDF
|
// Kompiliere LaTeX zu PDF
|
||||||
|
|||||||
Reference in New Issue
Block a user