|
3 | 3 | <head> |
4 | 4 | <meta charset="utf-8"> |
5 | 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 6 | +<!-- Everything the page needs is served from this origin: the flasher is |
| 7 | + vendored into ewt/ by installer/build-site.sh, the page script is app.js, |
| 8 | + and the manifests and firmware binaries sit alongside them. No external |
| 9 | + origin can supply code to a page that writes firmware over Web Serial. |
| 10 | + style-src allows inline because the page styles are in a <style> block and |
| 11 | + ESP Web Tools falls back to injecting <style> where adoptedStyleSheets is |
| 12 | + unavailable; blob: is allowed for connect because the flasher's dialog |
| 13 | + creates object URLs. frame-ancestors is omitted: it is ignored in a meta |
| 14 | + CSP and needs a real header. --> |
| 15 | +<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' blob:; form-action 'self'; base-uri 'none'"> |
6 | 16 | <title>Pool Controller — Web Installer</title> |
7 | 17 | <meta name="description" content="Flash the Connect 10 pool controller firmware to an ESP32-C6 straight from your browser."> |
8 | 18 | <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%231565C0' d='M2,15C3.67,14.25 5.33,13.5 7,13.17V5A3,3 0 0,1 10,2C11.31,2 12.42,2.83 12.83,4H10A1,1 0 0,0 9,5V6H14V5A3,3 0 0,1 17,2C18.31,2 19.42,2.83 19.83,4H17A1,1 0 0,0 16,5V14.94C18,14.62 20,13 22,13V15C19.78,15 17.56,17 15.33,17C13.11,17 10.89,15 8.67,15C6.44,15 4.22,16 2,17V15M14,8H9V10H14V8M14,12H9V13C10.67,13.16 12.33,14.31 14,14.79V12M2,19C4.22,18 6.44,17 8.67,17C10.89,17 13.11,19 15.33,19C17.56,19 19.78,17 22,17V19C19.78,19 17.56,21 15.33,21C13.11,21 10.89,19 8.67,19C6.44,19 4.22,20 2,21V19Z'/%3E%3C/svg%3E"> |
@@ -178,62 +188,7 @@ <h2>Project links</h2> |
178 | 188 | </footer> |
179 | 189 | </main> |
180 | 190 |
|
181 | | -<script type="module" src="https://unpkg.com/esp-web-tools@10/dist/web/install-button.js"></script> |
182 | | -<script> |
183 | | - // versions.json is generated by installer/build-site.sh, newest release first, |
184 | | - // with one manifest and one firmware binary per version. ESP Web Tools reads |
185 | | - // the manifest when the button is clicked, so switching versions is just a |
186 | | - // matter of re-pointing the button's manifest attribute. |
187 | | - const select = document.getElementById('version'); |
188 | | - const installer = document.getElementById('installer'); |
189 | | - const notes = document.getElementById('notes'); |
190 | | - const older = document.getElementById('older'); |
191 | | - const olderLatest = document.getElementById('older-latest'); |
192 | | - |
193 | | - function apply(entry, latest) { |
194 | | - installer.setAttribute('manifest', './' + entry.manifest); |
195 | | - notes.href = entry.notes; |
196 | | - olderLatest.textContent = latest; |
197 | | - older.hidden = entry.version === latest; |
198 | | - } |
199 | | - |
200 | | - fetch('./versions.json') |
201 | | - .then((r) => { |
202 | | - if (!r.ok) throw new Error('versions.json: HTTP ' + r.status); |
203 | | - return r.json(); |
204 | | - }) |
205 | | - .then((data) => { |
206 | | - const list = data.versions || []; |
207 | | - if (!list.length) throw new Error('no versions listed'); |
208 | | - |
209 | | - select.textContent = ''; |
210 | | - for (const entry of list) { |
211 | | - const opt = document.createElement('option'); |
212 | | - opt.value = entry.version; |
213 | | - opt.textContent = |
214 | | - entry.version + |
215 | | - (entry.version === data.latest ? ' (latest)' : '') + |
216 | | - (entry.published ? ' — ' + entry.published : ''); |
217 | | - select.append(opt); |
218 | | - } |
219 | | - select.disabled = list.length < 2; |
220 | | - select.value = data.latest; |
221 | | - apply(list.find((e) => e.version === data.latest) || list[0], data.latest); |
222 | | - |
223 | | - select.addEventListener('change', () => { |
224 | | - const entry = list.find((e) => e.version === select.value); |
225 | | - if (entry) apply(entry, data.latest); |
226 | | - }); |
227 | | - }) |
228 | | - .catch(() => { |
229 | | - // Leave the button on manifest.json, which build-site.sh always writes as |
230 | | - // a copy of the latest release's manifest, so installing still works. |
231 | | - select.textContent = ''; |
232 | | - const opt = document.createElement('option'); |
233 | | - opt.textContent = 'latest'; |
234 | | - select.append(opt); |
235 | | - select.disabled = true; |
236 | | - }); |
237 | | -</script> |
| 191 | +<script type="module" src="./ewt/install-button.js"></script> |
| 192 | +<script src="./app.js"></script> |
238 | 193 | </body> |
239 | 194 | </html> |
0 commit comments