docs/: add ToS-gate Base64 URLs mechanism

- docs/javascripts/tos-gate.js - new revealGated() function, intentionally no
  rel="noreferrer
- main.py - Added tos_gated_downloads(section_id, files, tos_url) macro;
  tos_checkbox kept for other uses
- mkdocs.yml - Added javascripts/tos-gate.js to extra_javascript
- overrides/main.html - New pins Referrer-Policy:
  strict-origin-when-cross-origin globally

Signed-off-by: Artur Raglis <artur.raglis@3mdeb.com>
This commit is contained in:
Artur Raglis
2026-05-17 18:43:41 +02:00
parent 3550f0019e
commit 8d0d41b5ee
7 changed files with 141 additions and 46 deletions
+52 -16
View File
@@ -121,37 +121,73 @@ instead. To embed an video simply type the following in markdown:
### Embedding ToS checkbox
A ToS acceptance checkbox can be added to any release page to gate binary
downloads behind a user acknowledgement. The feature is opt-in per page.
A ToS acceptance checkbox can be added to any page to gate binary downloads
and/or prose content behind a user acknowledgement. The feature is opt-in per
page.
**1. Add the checkbox macro** above the content you want to protect:
#### Gating download buttons
Use the `tos_gated_downloads` macro and pass a unique `section_id` together
with the list of files. Use the **group format** to preserve subsection
headings matching the original release layout:
```md
{{ tos_checkbox("unique-section-id") }}
{{ tos_gated_downloads("vendor-board-vXYZ-binaries", [
{"group": "Raw firmware image", "note": "(vendor_board_vX.Y.Z.rom)", "items": [
{"label": "sha256", "url": "https://dl.3mdeb.com/.../file.rom.sha256"},
{"label": "sha256.sig", "url": "https://dl.3mdeb.com/.../file.rom.sha256.sig"}
]},
{"group": "SBOM CycloneDX", "items": [
{"label": "sbom.json", "url": "https://dl.3mdeb.com/.../file.sbom.json"},
{"label": "sha256", "url": "https://dl.3mdeb.com/.../file.sbom.json.sha256"},
{"label": "sha256.sig", "url": "https://dl.3mdeb.com/.../file.sbom.json.sha256.sig"}
]}
]) }}
```
**2. Wrap the protected content** in an HTML div with a matching `id`:
Download links are **not** emitted into the HTML source - they are
base64-encoded in a `data-payload` attribute and injected by `tos-gate.js` only
after the user checks the box. This keeps URLs out of page source and prevents
them from being indexed.
Download buttons with groups example:
[`docs/variants/gigabyte_mz33-ar1/releases.md`][tos-example]
#### Optional argument (`tos_url`)
Overrides the default Terms of Service link:
```md
<div id="unique-section-id" class="tos-gate-content" markdown="1" style="display: none">
{{ tos_gated_downloads("...", [...], tos_url="https://example.com/terms") }}
```
...binary download buttons and related content...
#### Optional hiding prose content
Pass `prose_section_id` to make the same checkbox also show/hide one or more
blocks of descriptive text. Wrap each prose block in a div with a matching
`data-prose-group` attribute:
```md
{{ tos_gated_downloads("vendor-board-vXYZ-blobs",
[{"label": "blobs.zip", "url": "https://dl.3mdeb.com/.../blobs.zip"}],
prose_section_id="vendor-board-vXYZ-blobs-prose") }}
<div data-prose-group="vendor-board-vXYZ-blobs-prose"
class="tos-gate-content" markdown="1" style="display: none">
Further instructions that only make sense after downloading...
</div>
```
`tos_checkbox` accepts an optional `tos_url` argument to override the default
Terms of Service link:
Multiple divs sharing the same `data-prose-group` value are all toggled by
the single checkbox, so one gate can reveal several separate prose sections.
```md
{{ tos_checkbox("unique-section-id", tos_url="https://example.com/terms") }}
```
For pages with multiple release sections, use a distinct `section-id` per
release (e.g. `vendor-board-v100-binaries`, `vendor-board-v090-binaries`). See
[`docs/variants/gigabyte_mz33-ar1/releases.md`][tos-example] for example.
Combined buttons + prose example:
[`docs/variants/gigabyte_mz33-ar1/building-manual.md`][tos-prose-example]
[tos-example]: docs/variants/gigabyte_mz33-ar1/releases.md
[tos-prose-example]: docs/variants/gigabyte_mz33-ar1/building-manual.md
### Embedding subscribe forms
+28
View File
@@ -0,0 +1,28 @@
function revealGated(cb) {
const el = document.getElementById(cb.dataset.section);
const proseEls = cb.dataset.proseSection
? document.querySelectorAll(`[data-prose-group="${cb.dataset.proseSection}"]`)
: [];
if (!cb.checked) {
el.innerHTML = "";
proseEls.forEach(p => { p.style.display = "none"; });
return;
}
const files = JSON.parse(atob(el.dataset.payload));
// rel="noreferrer" is intentionally absent — it would strip the Referer
// header and break the MinIO bucket policy gate
el.innerHTML = files.map(f => {
if (f.group) {
const btns = f.items.map(item =>
`<a href="${item.url}" class="md-button">${item.label}</a>`
).join(" ");
const note = f.note ? ` <span>${f.note}</span>` : "";
return `<h4>${f.group}</h4><p>${btns}${note}</p>`;
}
return `<a href="${f.url}" class="md-button">${f.label}</a>`;
}).join("\n");
proseEls.forEach(p => { p.style.display = ""; });
}
@@ -46,14 +46,14 @@ then follow the steps below:
3. Download the package with necessary blobs and put it in proper directory:
{{ tos_checkbox("gigabyte-mz33-ar1-v090-blobs") }}
{{ tos_gated_downloads("gigabyte-mz33-ar1-v090-blobs",
[{"label": "Turin.zip", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/Turin.zip"}],
prose_section_id="gigabyte-mz33-ar1-v090-blobs-prose") }}
<div id="gigabyte-mz33-ar1-v090-blobs"
<div data-prose-group="gigabyte-mz33-ar1-v090-blobs-prose"
class="tos-gate-content" markdown="1"
style="display: none">
- Download the [blobs
package](https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/Turin.zip).
- Then unzip it to the following directory:
```bash
+15 -26
View File
@@ -73,23 +73,21 @@ Test results for this release can be found
### Binaries
#### Raw Dasharo image
[sha256][gigabyte_mz33_ar1_v0.9.0.rom_hash]{.md-button}
[sha256.sig][gigabyte_mz33_ar1_v0.9.0.rom_sig]{.md-button}
(gigabyte_mz33_ar1_v0.9.0.rom)
#### Update via BMC image
[sha256][gigabyte_mz33_ar1_v0.9.0.rbu_hash]{.md-button}
[sha256.sig][gigabyte_mz33_ar1_v0.9.0.rbu_sig]{.md-button}
(gigabyte_mz33_ar1_v0.9.0.rbu)
#### SBOM CycloneDX
[gigabyte_mz33_ar1_v0.9.0.sbom.json][gigabyte_mz33_ar1_v0.9.0.sbom.json_file]{.md-button}
[sha256][gigabyte_mz33_ar1_v0.9.0.sbom.json_hash]{.md-button}
[sha256.sig][gigabyte_mz33_ar1_v0.9.0.sbom.json_sig]{.md-button}
{{ tos_gated_downloads("gigabyte-mz33-ar1-v090-binaries", [
{"group": "Raw Dasharo image", "note": "(gigabyte_mz33_ar1_v0.9.0.rom)", "items": [
{"label": "sha256", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rom.sha256"},
{"label": "sha256.sig", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rom.sha256.sig"}
]},
{"group": "Update via BMC image", "note": "(gigabyte_mz33_ar1_v0.9.0.rbu)", "items": [
{"label": "sha256", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rbu.sha256"},
{"label": "sha256.sig", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rbu.sha256.sig"}
]},
{"group": "SBOM CycloneDX", "items": [
{"label": "sbom.json", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.sbom.json"},
{"label": "sha256", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.sbom.json.sha256"},
{"label": "sha256.sig", "url": "https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.sbom.json.sha256.sig"}
]}
]) }}
This is a Dasharo Pro Package release. For this platform, access to pre-built
binaries is provided exclusively through the
@@ -126,12 +124,3 @@ and their versions used to build the firmware images. The published SBOM
artifact is in CycloneDX format and can be viewed by SBOM tools, for example
[sbom-tools](https://github.com/sbom-tool/sbom-tools).
[gigabyte_mz33_ar1_v0.9.0.rom_hash]: https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rom.sha256
[gigabyte_mz33_ar1_v0.9.0.rom_sig]: https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rom.sha256.sig
[gigabyte_mz33_ar1_v0.9.0.rbu_hash]: https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rbu.sha256
[gigabyte_mz33_ar1_v0.9.0.rbu_sig]: https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.rbu.sha256.sig
[gigabyte_mz33_ar1_v0.9.0.sbom.json_file]: https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.sbom.json
[gigabyte_mz33_ar1_v0.9.0.sbom.json_hash]: https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.sbom.json.sha256
[gigabyte_mz33_ar1_v0.9.0.sbom.json_sig]: https://dl.3mdeb.com/open-source-firmware/Dasharo/gigabyte_mz33_ar1/uefi/v0.9.0/gigabyte_mz33_ar1_v0.9.0.sbom.json.sha256.sig
+35
View File
@@ -1,6 +1,41 @@
import base64
import json
def define_env(env):
""" Define macros for MkDocs """
@env.macro
def tos_gated_downloads(section_id, files, tos_url="https://www.dasharo.com/pages/terms/",
prose_section_id=None):
"""Render a ToS checkbox that reveals base64-encoded download links on acceptance.
files: flat list of {"label": str, "url": str} dicts, or grouped list of
{"group": str, "items": [...], "note": str (optional)} dicts.
URLs are not emitted into HTML source — base64-encoded in a data
attribute and injected by tos-gate.js when the checkbox is checked.
prose_section_id: when set, tos-gate.js also toggles all elements carrying
data-prose-group="{prose_section_id}". Multiple elements may share
the same value, allowing one checkbox to reveal several prose blocks.
"""
payload = base64.b64encode(json.dumps(files).encode()).decode()
checkbox_id = f"tos-cb-{section_id}"
prose_attr = f' data-prose-section="{prose_section_id}"' if prose_section_id else ""
return (
'<div class="tos-gate">'
f'<label class="tos-gate__label" for="{checkbox_id}">'
f'<input type="checkbox" id="{checkbox_id}" class="tos-gate__checkbox" '
f'data-section="{section_id}"{prose_attr} onchange="revealGated(this)"> '
'I confirm that I have read and agree to the '
f'<a href="{tos_url}" target="_blank" rel="noopener noreferrer">'
'Dasharo Terms of Service</a> and all applicable open-source '
'licensing terms governing this firmware release.'
'</label>'
f'<div id="{section_id}" class="tos-gate-content" data-payload="{payload}"></div>'
'</div>'
)
@env.macro
def tos_checkbox(section_id, tos_url="https://www.dasharo.com/pages/terms/"):
"""Render a ToS acceptance checkbox that reveals the section with the given id."""
+1
View File
@@ -35,6 +35,7 @@ extra:
extra_css:
- stylesheets/extra.css
extra_javascript:
- javascripts/tos-gate.js
- https://cdn.jsdelivr.net/npm/vega@5
- https://cdn.jsdelivr.net/npm/vega-lite@5
- https://cdn.jsdelivr.net/npm/vega-embed@6
+6
View File
@@ -0,0 +1,6 @@
{% extends "base.html" %}
{% block extrahead %}
{{ super() }}
<meta name="referrer" content="strict-origin-when-cross-origin">
{% endblock %}