fix: final review findings - thread safety, xss, cache
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user