Compare commits

..

2 Commits

Author SHA1 Message Date
678adc8f68 Merge feature/500-landing-platform-install : landing kbin embeds platform-detected install panels (ref #500)
Some checks are pending
License Headers / check (push) Waiting to run
2026-06-08 17:51:53 +02:00
b154894278 feat(toolbox): landing kbin embeds platform-detected install panels (ref #500)
The kbin.gk2.secubox.in landing page had a hand-written ordered list
showing only the iOS install steps.  Visitors on Android / Linux /
macOS / Windows had to follow a generic flow then go elsewhere to
get their proper artifacts.

Refactored : the install section now renders the same 5 platform
panels as /wg/onboard, with server-side UA sniffing to open the
right panel first.  Each panel keeps the same content (App Store
links / QR / .conf / .nmconnection / .mobileconfig / install
commands per OS).

Implementation : extracted _install_panels_html() from the prior
_render_onboard() so both endpoints render identical markup.  CSS
classes stay landing-local (a fresh <style> block) so the existing
landing design language is preserved.  No new endpoints ; the
landing.html.j2 receives `install_panels` + `install_platform`
context.

Visitor flow now : open kbin.gk2.secubox.in → "📥 Installer R3 sur
ton appareil" → already-open panel matches the visitor's device →
single click on the install button or QR scan.

Live verified on gk2 : curl with iPhone UA renders `id="install-ios"
open` first ; Linux UA renders `id="install-linux" open` first ;
HTTP 200, 28 KB rendered page.
2026-06-08 17:51:43 +02:00
3 changed files with 106 additions and 15 deletions

View File

@ -241,19 +241,40 @@ LXC toolbox-mitm-wg 10.100.0.62 R3 WireGuard
</div> </div>
</div> </div>
{# ── Install demo ── #} {# ── Install : auto-detected platform panels (Phase 8.2 #500) ── #}
<div class=section> <div class=section>
<h2>📥 Démo : installer le mode R3 portable</h2> <h2>📥 Installer R3 sur ton appareil</h2>
<ol class=steps> <p style="font-size:0.85rem;color:var(--dim);margin-bottom:0.8rem">
<li>Installer l'app <b>WireGuard</b> (gratuite, App Store / Play Store)</li> On a détecté <code>{{ install_platform }}</code> via ton navigateur — le panneau adapté
<li>Aller sur <a href=/wg/r3-install>🌐 page d'install R3</a> → scanner le QR avec l'app WireGuard</li> est ouvert en premier. Autre appareil ? Déplie le bon panneau ci-dessous.
<li>Activer le tunnel dans l'app WireGuard → icône VPN apparaît dans iOS</li> </p>
<li>Ouvrir n'importe quelle page web → bandeau ToolBox apparaît + rapport temps réel se remplit</li> <style>
<li>Désactiver le tunnel à tout moment → retour au surf normal</li> .install-panel{background:rgba(0,255,65,0.04);border:1px solid rgba(0,255,65,0.25);
</ol> border-radius:6px;padding:0.6rem 0.9rem;margin:0.45rem 0}
<p style="margin-top:0.6rem;font-size:0.78rem;color:var(--dim)"> .install-panel summary{cursor:pointer;font-size:0.95rem;color:var(--phos-peak,#00dd44);
Avantage R3 : marche hors-cabine (4G/5G, autre WiFi). Inclus tout le trafic (HTTPS + QUIC). list-style:none;outline:none}
Profile + CA bundlés dans un seul fichier .conf. .install-panel summary::-webkit-details-marker{display:none}
.install-panel[open] summary{margin-bottom:0.6rem}
.install-panel .emoji{font-size:1.1rem;margin-right:0.3rem}
.install-panel ol{padding-left:1.1rem;line-height:1.5;font-size:0.85rem}
.install-panel .btn{display:inline-block;padding:0.45rem 0.75rem;margin:0.25rem 0.2rem 0.25rem 0;
background:var(--purple,#6e40c9);color:#fff;text-decoration:none;border-radius:5px;
font-weight:bold;font-size:0.82rem}
.install-panel .btn.alt{background:transparent;border:1px solid var(--purple,#6e40c9);
color:var(--purple,#6e40c9)}
.install-panel code{background:rgba(0,0,0,0.4);padding:0.1rem 0.35rem;border-radius:3px;
font-size:0.8rem;color:var(--phos-peak,#00dd44)}
.install-panel .note{color:var(--dim,#888);font-size:0.78rem;margin-top:0.6rem;
border-left:2px solid var(--phos-hot,#ffb347);padding-left:0.6rem}
.install-panel img{max-width:100%;border-radius:5px;margin:0.4rem 0}
.install-panel pre{background:rgba(0,0,0,0.4);padding:0.5rem 0.7rem;border-radius:4px;
overflow-x:auto;font-size:0.78rem;margin:0.4rem 0}
</style>
{{ install_panels | safe }}
<p style="margin-top:0.8rem;font-size:0.78rem;color:var(--dim)">
Avantage R3 : marche hors-cabine (4G/5G, autre WiFi). Inclut tout le trafic (HTTPS).
Profil + CA bundlés. Le tunnel est révoquable à tout moment depuis Réglages.
Page équivalente standalone : <a href=/wg/onboard>/wg/onboard</a>.
</p> </p>
</div> </div>

View File

@ -1,3 +1,16 @@
secubox-toolbox (2.4.2-1~bookworm1) bookworm; urgency=medium
* Landing page kbin.gk2.secubox.in : la section 'Démo install R3'
est remplacée par les panneaux platform-detected du /wg/onboard.
UA sniff côté serveur (iOS / Android / Linux / macOS / Windows),
le panneau de la plate-forme du visiteur est ouvert en premier ;
les autres restent en details collapsed. Single source of truth :
_install_panels_html() partagé entre /wg/onboard et la landing.
Visiteur arrive sur kbin → voit immédiatement le bouton d'install
adapté à son device, sans devoir aller sur une page tierce.
-- Gérald Kerma <devel@cybermind.fr> lun., 08 juin 2026 15:51:43 +0000
secubox-toolbox (2.4.1-1~bookworm1) bookworm; urgency=medium secubox-toolbox (2.4.1-1~bookworm1) bookworm; urgency=medium
* Phase 8.1 perf (#500) — mitm-wg CPU bottleneck under multi-peer. * Phase 8.1 perf (#500) — mitm-wg CPU bottleneck under multi-peer.

View File

@ -411,16 +411,73 @@ async def cumulative_stats_json() -> dict:
return _cumulative_stats() return _cumulative_stats()
def _ua_platform(ua: str) -> str:
"""Cheap UA sniff. Same logic as /wg/onboard so the auto-open panel
matches between the two pages."""
ua = (ua or "").lower()
if "iphone" in ua or "ipad" in ua or "ios" in ua:
return "ios"
if "android" in ua:
return "android"
if "macintosh" in ua or "mac os x" in ua:
return "macos"
if "windows" in ua:
return "windows"
if "linux" in ua:
return "linux"
return "other"
def _install_panels_html(platform: str) -> str:
"""Reusable platform-detected install panels for both
/wg/onboard and the landing page. Same content, same CSS classes
so styling stays consistent (the landing page injects matching
classes via its own style block)."""
panels = {
"ios": ("🍎 iPhone / iPad", "ios"),
"android": ("🤖 Android", "android"),
"linux": ("🐧 Linux", "linux"),
"macos": ("🍏 macOS", "macos"),
"windows": ("🪟 Windows", "windows"),
}
order = [platform] + [k for k in panels if k != platform]
order = [k for i, k in enumerate(order) if k in panels and k not in order[:i]]
sections = []
for key in order:
title, slug = panels[key]
body = _ONBOARD_BODY[slug]
open_attr = " open" if key == order[0] else ""
sections.append(
f'<details class="install-panel" id="install-{slug}"{open_attr}>'
f'<summary><span class="emoji">{title.split()[0]}</span> '
f'<b>{title}</b></summary>{body}</details>'
)
return "\n".join(sections)
@router.get("/landing", response_class=HTMLResponse) @router.get("/landing", response_class=HTMLResponse)
@router.get("/cabine", response_class=HTMLResponse) @router.get("/cabine", response_class=HTMLResponse)
async def landing(request: Request) -> HTMLResponse: async def landing(request: Request) -> HTMLResponse:
"""Public landing page for the cabine — shown on kbin.gk2.secubox.in. """Public landing page for the cabine — shown on kbin.gk2.secubox.in.
Visitor-facing demo of the project : pitch + 4 levels + install + live Visitor-facing demo of the project : pitch + 4 levels + install + live
cumulative anonymous stats + open source license + contact.""" cumulative anonymous stats + open source license + contact.
Phase 8.2 (#500) — embeds the same platform-detected install
panels as /wg/onboard so visitors get a one-click flow matching
their device right on the landing page.
"""
stats = _cumulative_stats() stats = _cumulative_stats()
return HTMLResponse(_env.get_template("landing.html.j2").render(stats=stats), platform = _ua_platform(request.headers.get("user-agent") or "")
headers={"Cache-Control": "public, max-age=60"}) install_panels = _install_panels_html(platform)
return HTMLResponse(
_env.get_template("landing.html.j2").render(
stats=stats,
install_panels=install_panels,
install_platform=platform,
),
headers={"Cache-Control": "private, max-age=60, no-transform"},
)
@router.get("/ca/webclip-cabine.mobileconfig") @router.get("/ca/webclip-cabine.mobileconfig")