import { launch } from './serve.mjs'; const { page, browser } = await launch(); const res = await page.evaluate(async () => { const out = {}; const mk = () => document.createElement('houseplan-card'); const sr = (c) => c.shadowRoot || c.renderRoot; // 1) пустая инсталляция: ноль устройств/зон, конфиг с пространством без комнат const c1 = mk(); c1.setConfig({ type: 'custom:houseplan-card' }); document.body.appendChild(c1); c1.hass = { language:'en', locale:{language:'en'}, devices:{}, entities:{}, areas:{}, states:{}, callWS: async (m) => m.type==='houseplan/config/get' ? { config:{ spaces:[{ id:'s1', title:'Empty', plan_url:null, aspect:1.4, view_box:[0,0,1,1], rooms:[], segments:[] }], markers:[], settings:{} }, rev:1 } : { layout:{} }, connection:{ subscribeEvents: async()=>()=>{} } }; await new Promise(r=>setTimeout(r,150)); c1.hass = { ...c1.hass }; await c1.updateComplete; await new Promise(r=>setTimeout(r,50)); await c1.updateComplete; out.emptyDevices = c1._devices.length; out.emptyRenders = !!sr(c1).querySelector('.stage'); out.emptyCount = sr(c1).querySelector('.count')?.textContent.trim(); c1.remove(); // 2) XSS в именах комнат и устройств const c2 = mk(); c2.setConfig({ type: 'custom:houseplan-card' }); document.body.appendChild(c2); const evil = 'bold'; c2.hass = { language:'en', locale:{language:'en'}, devices:{ d1:{ id:'d1', name: evil, model:'M', area_id:'a1', identifiers:[['x','1']] } }, entities:{}, areas:{ a1:{ area_id:'a1', name:'A1' } }, states:{}, callWS: async (m) => m.type==='houseplan/config/get' ? { config:{ spaces:[{ id:'s1', title:'S', plan_url:null, aspect:1, view_box:[0,0,1,1], rooms:[{ id:'r1', name: evil, area:'a1', poly:[[0.1,0.1],[0.9,0.1],[0.9,0.9],[0.1,0.9]] }], segments:[] }], markers:[], settings:{} }, rev:1 } : { layout:{} }, connection:{ subscribeEvents: async()=>()=>{} } }; await new Promise(r=>setTimeout(r,150)); c2.hass = { ...c2.hass }; await c2.updateComplete; await new Promise(r=>setTimeout(r,50)); await c2.updateComplete; out.xssPwned = !!window.__pwned; const lbl = sr(c2).querySelector('.roomlabel'); out.xssLabelIsText = lbl ? lbl.innerHTML.includes('<img') || lbl.textContent.includes('