74 lines
2.9 KiB
JavaScript
74 lines
2.9 KiB
JavaScript
// @ts-check
|
||
// Issue #213: Stored XSS über Kontobezeichnungen im KI-Vorschlag-Badge.
|
||
//
|
||
// Das Badge liest die Kontobezeichnung aus den <option>-Elementen (option.text
|
||
// ist bereits dekodiert) und baut daraus die Anzeige. Einen gespeicherten
|
||
// KI-Vorschlag kann der Test ohne Ollama nicht erzeugen, und bestehende Konten
|
||
// darf er nicht umbenennen. Er legt deshalb im Browser eine Option mit
|
||
// Schadcode-Bezeichnung an und ruft _showKiBadgeDone() direkt auf.
|
||
|
||
const { test, expect } = require('@playwright/test')
|
||
const { uploadBeleg, cleanupBeleg } = require('../helpers/app')
|
||
|
||
const PAYLOAD = '<img src=x onerror="window.__xss213=1">'
|
||
|
||
test.describe('KI-Vorschlag-Badge', () => {
|
||
let belegId = 0
|
||
|
||
test.afterEach(async ({ page }) => {
|
||
await cleanupBeleg(page, belegId)
|
||
belegId = 0
|
||
})
|
||
|
||
test('Kontobezeichnungen und KI-Werte werden nur als Text angezeigt', async ({ page }) => {
|
||
const { id } = await uploadBeleg(page)
|
||
belegId = id
|
||
|
||
// Ist die KI-Sektion in dieser Instanz aus, fehlen Badge und Skript:
|
||
// dann beides nachladen (ohne Vorschlag, ohne automatische Analyse).
|
||
if (await page.locator('#ki-badge').count() === 0) {
|
||
await page.evaluate(() => {
|
||
const el = document.createElement('div')
|
||
el.id = 'ki-badge'
|
||
el.dataset.belegId = '0'
|
||
el.dataset.kiAktiv = 'false'
|
||
el.dataset.kiVorschlag = '[]'
|
||
document.querySelector('main, body').appendChild(el)
|
||
})
|
||
await page.addScriptTag({ url: '/static/js/beleg-ki.js' })
|
||
}
|
||
|
||
await page.evaluate(payload => {
|
||
for (const [selId, value] of [['kategorie_konto_id', '999001'], ['zahlungskonto_id', '999002']]) {
|
||
const opt = document.createElement('option')
|
||
opt.value = value
|
||
opt.textContent = 'Bank' + payload
|
||
document.getElementById(selId).appendChild(opt)
|
||
}
|
||
// eslint-disable-next-line no-undef
|
||
_showKiBadgeDone([{
|
||
buchungstyp: 'Ausgabe' + payload,
|
||
kategorie_konto_id: '999001',
|
||
zahlungskonto_id: '999002',
|
||
supplier_name: 'Lieferant' + payload,
|
||
supplier_found: false,
|
||
betrag_netto: '100',
|
||
ust_satz: '19' + payload,
|
||
}, { betrag_netto: '10', ust_satz: 7 }])
|
||
}, PAYLOAD)
|
||
|
||
const badge = page.locator('#ki-badge')
|
||
await expect(badge).toContainText('KI-Vorschlag:')
|
||
await expect(badge).toContainText('Kategorie: Bank' + PAYLOAD)
|
||
await expect(badge).toContainText('Zahlung: Bank' + PAYLOAD)
|
||
await expect(badge).toContainText('Lieferant: Lieferant' + PAYLOAD)
|
||
await expect(badge).toContainText('(neu – bitte prüfen)')
|
||
await expect(badge).toContainText('Zeile 1: Netto 100,00 € | USt 19% 19,00 € | Brutto 119,00 €')
|
||
await expect(badge).toContainText('Zeile 2: Netto 10,00 € | USt 7% 0,70 € | Brutto 10,70 €')
|
||
await expect(badge).toContainText('(bitte als weitere Buchung erfassen)')
|
||
await expect(badge.locator('img')).toHaveCount(0)
|
||
|
||
await page.waitForTimeout(300)
|
||
expect(await page.evaluate(() => /** @type {any} */ (window).__xss213)).toBeUndefined()
|
||
})
|
||
})
|