100 lines
4 KiB
JavaScript
100 lines
4 KiB
JavaScript
// @ts-check
|
|
// Fix #200 / #202: Mehrere SettingsController-Endpoints (Logo-Upload,
|
|
// Logo-Löschen, LLM-Test, CSV-Bankimport-Formate) prüften
|
|
// Auth::requireAdmin() nicht, obwohl der Bereich laut Code-Kommentar bei
|
|
// update() bewusst admin-pflichtig sein soll. Ein normaler "user"-Account
|
|
// konnte damit das Firmenlogo hochladen/löschen, Bankimport-Formate
|
|
// anlegen/ändern/löschen und den LLM-Test auslösen.
|
|
// Dieser Test prüft die Durchsetzung auf HTTP-Ebene, die die PHP-Suite
|
|
// nicht erreicht (Router-Guard, Auth::requireAdmin()).
|
|
|
|
const { test, expect } = require('@playwright/test')
|
|
const { uniqueTag } = require('../helpers/app')
|
|
|
|
test.describe('Autorisierung: Settings-Verwaltungsendpoints nur für Admins (Fix #200)', () => {
|
|
test('Nicht-Admin wird von Logo-, Bankimport- und LLM-Test-Endpoints ausgesperrt', async ({ page, browser }) => {
|
|
const username = uniqueTag('noadmin').toLowerCase().replace(/[^a-z0-9-]/g, '').slice(0, 64)
|
|
const password = 'TempPass123!'
|
|
|
|
await page.goto('/useradmin')
|
|
await page.fill('#field-username', username)
|
|
await page.fill('#field-password', password)
|
|
await page.click('#submit-btn')
|
|
await page.waitForURL('/useradmin')
|
|
|
|
const row = page.locator('tr', { hasText: username })
|
|
await expect(row).toBeVisible()
|
|
|
|
try {
|
|
const context = await browser.newContext({ storageState: { cookies: [], origins: [] } })
|
|
const userPage = await context.newPage()
|
|
await userPage.goto('/login')
|
|
await userPage.fill('#username', username)
|
|
await userPage.fill('#password', password)
|
|
await userPage.click('form[action="/login"] button[type="submit"]')
|
|
await userPage.waitForURL(url => !url.pathname.startsWith('/login'))
|
|
|
|
await userPage.goto('/settings')
|
|
const csrfToken = await userPage.evaluate(() => document.querySelector('meta[name="csrf-token"]')?.content || '')
|
|
expect(csrfToken).not.toBe('')
|
|
|
|
const headers = { 'X-CSRF-Token': csrfToken }
|
|
|
|
const bankImportGet = await userPage.request.get('/settings/bankimport')
|
|
expect(bankImportGet.status()).toBe(403)
|
|
|
|
const uploadLogo = await userPage.request.post('/settings/logo', {
|
|
headers,
|
|
multipart: { logo: { name: 'logo.png', mimeType: 'image/png', buffer: Buffer.from([]) } },
|
|
})
|
|
expect(uploadLogo.status()).toBe(403)
|
|
|
|
const deleteLogo = await userPage.request.post('/settings/logo/delete', { headers, form: {} })
|
|
expect(deleteLogo.status()).toBe(403)
|
|
|
|
const llmTest = await userPage.request.post('/settings/llm-test', { headers, form: {} })
|
|
expect(llmTest.status()).toBe(403)
|
|
|
|
const createFormat = await userPage.request.post('/settings/bankimport/create', {
|
|
headers,
|
|
form: { name: 'X', kuerzel: 'X' },
|
|
})
|
|
expect(createFormat.status()).toBe(403)
|
|
|
|
const suggest = await userPage.request.post('/settings/bankimport/suggest', {
|
|
headers,
|
|
data: {},
|
|
})
|
|
expect(suggest.status()).toBe(403)
|
|
|
|
const dismiss = await userPage.request.post('/settings/bankimport/dismiss-suggestion', { headers, form: {} })
|
|
expect(dismiss.status()).toBe(403)
|
|
|
|
const updateField = await userPage.request.post('/settings/bankimport/1/field', {
|
|
headers,
|
|
form: { field: 'name', value: 'X' },
|
|
})
|
|
expect(updateField.status()).toBe(403)
|
|
|
|
const deleteFormat = await userPage.request.post('/settings/bankimport/1/delete', { headers, form: {} })
|
|
expect(deleteFormat.status()).toBe(403)
|
|
|
|
for (const response of [bankImportGet, uploadLogo, deleteLogo, llmTest, createFormat, suggest, dismiss, updateField, deleteFormat]) {
|
|
await expect(response.text()).resolves.toContain('Kein Zugriff')
|
|
}
|
|
|
|
await context.close()
|
|
} finally {
|
|
const delForm = row.locator('form[action$="/delete"]')
|
|
if (await delForm.count() > 0) {
|
|
await delForm.locator('button[type="submit"]').click()
|
|
await page.waitForLoadState('networkidle')
|
|
}
|
|
}
|
|
})
|
|
|
|
test('Admin darf /settings/bankimport weiterhin aufrufen (kein 403)', async ({ page }) => {
|
|
const response = await page.goto('/settings/bankimport')
|
|
expect(response.status()).not.toBe(403)
|
|
})
|
|
})
|