Ajoute le support d'un jeton d'accès pour les serveurs ntfy protégés
Certains serveurs ntfy auto-hébergés (ex: ntfy.arkel.fr) renvoient
403 Forbidden sans authentification. Un nouveau champ "Jeton d'accès"
(optionnel, type password) sur /settings permet de renseigner un token
qui sera envoyé comme "Authorization: Bearer ..." à chaque publication,
pour les rappels réels comme pour le bouton de test. La page /aide
documente le cas 403 et la marche à suivre.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@ -185,3 +185,68 @@ def test_test_ntfy_logs_to_journal():
|
||||
logs = models.load_logs("alice")
|
||||
# L'entrée la plus récente doit être l'échec du test (message contient "Test pointeuse")
|
||||
assert any(l["event"] == "échec" and "Test pointeuse" in l["message"] for l in logs)
|
||||
|
||||
|
||||
# ── Jeton d'accès ntfy (serveur protégé) ─────────────────────────────────────
|
||||
|
||||
def test_send_ntfy_passes_authorization_header(monkeypatch):
|
||||
"""Quand un token est fourni, send_ntfy doit envoyer un header Authorization: Bearer."""
|
||||
import notifications
|
||||
captured = {}
|
||||
|
||||
class _DummyReq:
|
||||
def __init__(self, url, data, headers, method):
|
||||
captured["url"] = url
|
||||
captured["headers"] = headers
|
||||
captured["method"] = method
|
||||
|
||||
class _DummyResp:
|
||||
def close(self): pass
|
||||
|
||||
def _fake_urlopen(req, timeout):
|
||||
captured["timeout"] = timeout
|
||||
return _DummyResp()
|
||||
|
||||
monkeypatch.setattr(notifications.urllib.request, "Request", _DummyReq)
|
||||
monkeypatch.setattr(notifications.urllib.request, "urlopen", _fake_urlopen)
|
||||
|
||||
ok = notifications.send_ntfy(
|
||||
"https://ntfy.example", "topic-x",
|
||||
"msg", "titre", user_id="alice", token="tk_abc123",
|
||||
)
|
||||
assert ok is True
|
||||
assert captured["headers"]["Authorization"] == "Bearer tk_abc123"
|
||||
|
||||
|
||||
def test_send_ntfy_omits_authorization_when_no_token(monkeypatch):
|
||||
"""Sans token, pas de header Authorization."""
|
||||
import notifications
|
||||
captured = {}
|
||||
|
||||
class _DummyReq:
|
||||
def __init__(self, url, data, headers, method):
|
||||
captured["headers"] = headers
|
||||
|
||||
class _DummyResp:
|
||||
def close(self): pass
|
||||
|
||||
monkeypatch.setattr(notifications.urllib.request, "Request", _DummyReq)
|
||||
monkeypatch.setattr(notifications.urllib.request, "urlopen", lambda req, timeout: _DummyResp())
|
||||
|
||||
notifications.send_ntfy("https://x", "t", "m", "ti", user_id=None, token="")
|
||||
assert "Authorization" not in captured["headers"]
|
||||
|
||||
|
||||
def test_settings_save_persists_ntfy_token():
|
||||
"""Le token saisi dans /settings doit être persisté."""
|
||||
models.save_notif_config("alice", ntfy_topic="t", ntfy_server="https://ntfy.sh")
|
||||
client.post("/settings", cookies=COOKIES, data={
|
||||
"ntfy_topic": "topic-persisted",
|
||||
"ntfy_server": "https://ntfy.arkel.fr",
|
||||
"ntfy_token": "tk_persisted_123",
|
||||
"rappel_debut_h": "8",
|
||||
"rappel_fin_h": "19",
|
||||
})
|
||||
cfg = models.load_notif_config("alice")
|
||||
assert cfg["ntfy_token"] == "tk_persisted_123"
|
||||
assert cfg["ntfy_topic"] == "topic-persisted"
|
||||
|
||||
Reference in New Issue
Block a user