fix: final review findings - thread safety, xss, cache

This commit is contained in:
2026-08-16 17:35:13 +08:00
parent a0f8873b7a
commit f7cffe27d9
8 changed files with 157 additions and 39 deletions
+18 -6
View File
@@ -9,12 +9,24 @@ window.loadAppList = async function () {
const apps = JSON.parse(await bridge.call('listApps'));
const grid = document.getElementById('app-grid');
const render = (list) => {
grid.innerHTML = list.map(a => `
<button class="cell" data-pkg="${a.packageName}">
<img class="ic" src="${a.iconBase64 || ''}" alt="">
<span class="lbl">${a.label}</span>
</button>`).join('');
grid.querySelectorAll('.cell').forEach(el => el.onclick = () => bridge.call('launchApp', el.dataset.pkg));
grid.textContent = '';
// 用 createElement + textContent/dataset 渲染,避免 innerHTML 拼接用户数据(XSS
// Render with createElement + textContent/dataset to avoid innerHTML user data (XSS)
list.forEach(a => {
const btn = document.createElement('button');
btn.className = 'cell';
btn.dataset.pkg = a.packageName;
const img = document.createElement('img');
img.className = 'ic';
img.src = a.iconBase64 || '';
img.alt = '';
const lbl = document.createElement('span');
lbl.className = 'lbl';
lbl.textContent = a.label;
btn.append(img, lbl);
btn.onclick = () => bridge.call('launchApp', btn.dataset.pkg);
grid.appendChild(btn);
});
};
render(apps);
document.getElementById('app-search').oninput = (e) => {
+22 -7
View File
@@ -9,13 +9,28 @@ window.loadWebAppList = async function () {
const apps = JSON.parse(await bridge.call('fetchWebApps'));
const grid = document.getElementById('web-grid');
const render = (list) => {
grid.innerHTML = list.map(a => `
<button class="wcell" data-id="${a.id}" data-url="${a.url}">
<img class="ic" src="${a.icon}" alt="">
<span class="lbl">${a.name}</span>
<span class="tag">${a.offline ? '离线' : '在线'}</span>
</button>`).join('');
grid.querySelectorAll('.wcell').forEach(el => el.onclick = () => bridge.call('openWebApp', el.dataset.id));
grid.textContent = '';
// 用 createElement + textContent/dataset 渲染,避免 innerHTML 拼接远端数据(XSS
// Render with createElement + textContent/dataset to avoid innerHTML remote data (XSS)
list.forEach(a => {
const btn = document.createElement('button');
btn.className = 'wcell';
btn.dataset.id = a.id;
btn.dataset.url = a.url;
const img = document.createElement('img');
img.className = 'ic';
img.src = a.icon;
img.alt = '';
const lbl = document.createElement('span');
lbl.className = 'lbl';
lbl.textContent = a.name;
const tag = document.createElement('span');
tag.className = 'tag';
tag.textContent = a.offline ? '离线' : '在线';
btn.append(img, lbl, tag);
btn.onclick = () => bridge.call('openWebApp', btn.dataset.id);
grid.appendChild(btn);
});
};
render(apps);
document.getElementById('web-search').oninput = (e) => {