mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-14 05:06:54 +00:00
daily-focus-board: harden canvas (DNS-rebind, XSS, destructive write) + skill a11y
Resolves the remaining Copilot review comments. Canvas extension (board-core.mjs, board.html): - DNS-rebinding: pin the Host header to the exact 127.0.0.1:<port> authority and require a per-server capability token (minted at startup, embedded in the served page, sent as x-board-token) on ALL /api/* routes -- so GET /api/state can't leak task data and POSTs can't be forged. Mirrors extensions/signals-dashboard. - Destructive write: loadDoc only synthesizes a fresh board for ENOENT and now propagates I/O + JSON parse errors, so a transient/malformed state file is never overwritten by a later mutation. - XSS: escape emoji (from the seed / add_task action) at render, like title/unit. Skill (board.template.html, sample-board.html): - a11y: each task card gets role=group + aria-label so screen readers get task context. - counters: step=1 on the goal/update number inputs to match the positive-integer contract. Verified headless (35/35): token gates reads+writes, CSRF + foreign-Host refused, malformed file left intact. Repo plugin + skill validation green. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: cb356aa8-0af2-48f3-b3c6-8086c69d5308
This commit is contained in:
@@ -223,7 +223,7 @@
|
||||
<div class="addtask-form" id="addtaskform" style="display:none">
|
||||
<input id="ntitle" placeholder="what needs doing?"/>
|
||||
<label class="addtask-count"><input type="checkbox" id="niscount"/> count toward a number</label>
|
||||
<span id="ncountfields" class="ncount-fields" style="display:none"><input type="number" id="ngoal" min="1" placeholder="goal"/><input id="nunit" placeholder="unit (pages, reps…)"/></span>
|
||||
<span id="ncountfields" class="ncount-fields" style="display:none"><input type="number" id="ngoal" min="1" step="1" placeholder="goal"/><input id="nunit" placeholder="unit (pages, reps…)"/></span>
|
||||
<button id="naddbtn">add</button>
|
||||
<button id="ncancel" class="soft">cancel</button>
|
||||
</div>
|
||||
@@ -324,6 +324,7 @@ function render(){
|
||||
const c=document.createElement("div");
|
||||
const q=quadOf(t), tag=tagOf(t);
|
||||
c.className="card "+st+(carried?" carried":"")+(state.focus===t.id?" focused":"")+(q?" q-"+q:"");
|
||||
c.setAttribute("role","group");c.setAttribute("aria-label",t.title||"task");
|
||||
c.dataset.cardid=t.id;
|
||||
const dh=dueStr(t);
|
||||
const rmHtml=t.added?`<button class="rmbtn" data-rmtask="${t.id}" title="remove this task" aria-label="remove ${escAttr(t.title)}">🗑</button>`:"";
|
||||
@@ -341,7 +342,7 @@ function render(){
|
||||
<span class="pill ${st}">${LABEL[st]}</span>
|
||||
<button class="fbtn" data-focus="${t.id}" title="focus on this" aria-label="focus on ${escAttr(t.title)}">🎯</button>${rmHtml}</div>
|
||||
<div class="bar"><div class="fill" data-fill="${t.id}"></div></div>
|
||||
<div class="stepctl">update: <input type="number" data-cin="${t.id}" value="${v}" min="0"/>
|
||||
<div class="stepctl">update: <input type="number" data-cin="${t.id}" value="${v}" min="0" step="1"/>
|
||||
<button data-cset="${t.id}">set</button><button data-cinc="${t.id}">+${inc.toLocaleString()}</button></div>${metaHtml}`;
|
||||
cardsEl.appendChild(c);
|
||||
requestAnimationFrame(()=>{const f=cardsEl.querySelector(`[data-fill="${t.id}"]`);if(f)f.style.width=pct+"%";});
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
<div class="addtask-form" id="addtaskform" style="display:none">
|
||||
<input id="ntitle" placeholder="what needs doing?"/>
|
||||
<label class="addtask-count"><input type="checkbox" id="niscount"/> count toward a number</label>
|
||||
<span id="ncountfields" class="ncount-fields" style="display:none"><input type="number" id="ngoal" min="1" placeholder="goal"/><input id="nunit" placeholder="unit (pages, reps…)"/></span>
|
||||
<span id="ncountfields" class="ncount-fields" style="display:none"><input type="number" id="ngoal" min="1" step="1" placeholder="goal"/><input id="nunit" placeholder="unit (pages, reps…)"/></span>
|
||||
<button id="naddbtn">add</button>
|
||||
<button id="ncancel" class="soft">cancel</button>
|
||||
</div>
|
||||
@@ -332,6 +332,7 @@ function render(){
|
||||
const c=document.createElement("div");
|
||||
const q=quadOf(t), tag=tagOf(t);
|
||||
c.className="card "+st+(carried?" carried":"")+(state.focus===t.id?" focused":"")+(q?" q-"+q:"");
|
||||
c.setAttribute("role","group");c.setAttribute("aria-label",t.title||"task");
|
||||
c.dataset.cardid=t.id;
|
||||
const dh=dueStr(t);
|
||||
const rmHtml=t.added?`<button class="rmbtn" data-rmtask="${t.id}" title="remove this task" aria-label="remove ${escAttr(t.title)}">🗑</button>`:"";
|
||||
@@ -349,7 +350,7 @@ function render(){
|
||||
<span class="pill ${st}">${LABEL[st]}</span>
|
||||
<button class="fbtn" data-focus="${t.id}" title="focus on this" aria-label="focus on ${escAttr(t.title)}">🎯</button>${rmHtml}</div>
|
||||
<div class="bar"><div class="fill" data-fill="${t.id}"></div></div>
|
||||
<div class="stepctl">update: <input type="number" data-cin="${t.id}" value="${v}" min="0"/>
|
||||
<div class="stepctl">update: <input type="number" data-cin="${t.id}" value="${v}" min="0" step="1"/>
|
||||
<button data-cset="${t.id}">set</button><button data-cinc="${t.id}">+${inc.toLocaleString()}</button></div>${metaHtml}`;
|
||||
cardsEl.appendChild(c);
|
||||
requestAnimationFrame(()=>{const f=cardsEl.querySelector(`[data-fill="${t.id}"]`);if(f)f.style.width=pct+"%";});
|
||||
|
||||
Reference in New Issue
Block a user