Appairage du téléphone, en-têtes de licence (2.1.0)

Recopier un jeton de trente-trois caractères sur un clavier tactile n'était pas
un réglage, c'était une corvée. On ouvre désormais une fenêtre depuis le
serveur, on appuie sur Appairer côté téléphone, et c'est fait.

Le jeton n'est pas pour autant distribué : ouvrir la fenêtre l'exige déjà,
elle dure deux minutes, se referme dès qu'un appareil s'est servi, et ne
répond qu'à une adresse privée. Le champ de saisie reste là pour qui préfère
le coller.

Les cinquante fichiers de code portent en outre leur notice de licence, comme
la GPL le recommande. Elle est en français, comme le reste ; le texte qui fait
foi demeure celui de LICENSE, non traduit.
This commit is contained in:
tuxgyver committed 2026-09-13 20:15:14 +02:00
1 parent b3ddc2117b
commit 51b60cda70
53 files changed
+717 -4

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
+10
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Point d'entrée : `python -m noxely_server`."""
from __future__ import annotations
+60
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""API HTTP du serveur Noxely.
Le client Android ne consomme que `/api/health`, `/api/library` et `/api/media/{id}/file` :
@@ -7,6 +17,8 @@ mobile doit pouvoir se contenter d'un sondage bref, c'est là qu'est le gain de
from __future__ import annotations
import asyncio
import ipaddress
import time
from contextlib import asynccontextmanager
from pathlib import Path
@@ -19,6 +31,7 @@ from .storage import Storage
from .workers import Downloader, Watcher, safe_name
VERSION = "1.0.0"
PAIRING_WINDOW_SECONDS = 120
WEB_DIR = Path(__file__).parent / "web"
config = config_module.load()
@@ -180,6 +193,53 @@ def queue_state() -> dict:
return {"items": [m.public() for m in pending if m.state != "ready"][:50]}
#: Fenêtre d'appairage : instant d'expiration, ou None si elle est fermée.
_pairing_until: float | None = None
def _is_private(host: str) -> bool:
"""Le réseau local, et lui seul."""
try:
address = ipaddress.ip_address(host)
return address.is_private or address.is_loopback
except ValueError:
return host in ("localhost", "")
@app.post("/api/pair/open", dependencies=[Depends(authorised)])
def open_pairing() -> dict:
"""Ouvre une fenêtre de deux minutes pendant laquelle un appareil du réseau local peut
réclamer le jeton. Fermée le reste du temps : sinon le jeton ne protégerait plus rien."""
global _pairing_until
_pairing_until = time.time() + PAIRING_WINDOW_SECONDS
return {"open": True, "seconds": PAIRING_WINDOW_SECONDS}
@app.get("/api/pair/state", dependencies=[Depends(authorised)])
def pairing_state() -> dict:
remaining = int(_pairing_until - time.time()) if _pairing_until else 0
return {"open": remaining > 0, "seconds": max(0, remaining)}
@app.post("/api/pair")
def pair(request: Request) -> dict:
"""Livre le jeton à un appareil du réseau local, pendant la fenêtre d'appairage.
La fenêtre se referme dès qu'un appareil s'est servi : une ouverture, un appairage.
"""
global _pairing_until
client = request.client.host if request.client else ""
if not _pairing_until or time.time() > _pairing_until:
raise HTTPException(
status_code=403,
detail="Aucun appairage en cours. Ouvrez-en un depuis l'interface du serveur.",
)
if not _is_private(client):
raise HTTPException(status_code=403, detail="Appairage réservé au réseau local")
_pairing_until = None
return {"token": config.token, "name": "Noxely", "version": VERSION}
@app.get("/api/bootstrap")
def bootstrap(request: Request) -> dict:
"""Livre le jeton — uniquement à une requête venue de la machine elle-même.
+10
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Configuration du serveur Noxely, lue de l'environnement.
Aucune valeur sensible n'est écrite dans le dépôt : le jeton et les chemins viennent d'un
+10
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Catalogues libres et annuaire radio, portés depuis le client Android.
Les pièges vérifiés côté mobile restent valables ici et sont conservés en commentaire :
+10
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Recherche dans les catalogues libres de droits."""
from __future__ import annotations
+10
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Annuaire des stations et lecture des métadonnées ICY."""
from __future__ import annotations
+10
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Index des médias et des guets, en SQLite.
Les fichiers vivent sur le disque ; la base ne porte que leurs métadonnées et l'état de la
+21
View File
@@ -1,4 +1,15 @@
<!doctype html>
<!--
Noxely — collecte côté serveur, écoute hors connexion côté mobile.
Copyright © 2026 Johnny (tuxgyver)
Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
selon les termes de la GNU General Public License, version 3 ou ultérieure,
telle que publiée par la Free Software Foundation.
Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
-->
<html lang="fr">
<head>
<meta charset="utf-8">
@@ -46,6 +57,7 @@
<span class="grow" style="flex:1"></span>
<input type="password" id="token" placeholder="Jeton" style="width:190px">
<button class="ghost" onclick="saveToken()">Enregistrer</button>
<button class="go" onclick="openPairing()">📱 Appairer</button>
</header>
<main>
<div class="tabs">
@@ -245,6 +257,15 @@ async function sweep() {
loadWatches();
}
async function openPairing() {
try {
const { seconds } = await api('/pair/open', { method: 'POST' });
alert(`Appairage ouvert pour ${seconds} secondes.\n\n` +
`Sur le téléphone : Réglages ▸ Connexion ▸ Appairer.\n` +
`La fenêtre se referme dès qu'un appareil s'est servi.`);
} catch (e) { alert('Appairage impossible : ' + e); }
}
const esc = (s) => String(s).replace(/[&<>"']/g, (c) =>
({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
+10
View File
@@ -1,3 +1,13 @@
# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Tâches de fond : file de téléchargement, guet radio et enregistrement.
C'est ici que se déplace la consommation qui pesait sur le téléphone : le serveur balaie les