diff --git a/app/delivery.py b/app/delivery.py
index 70c5c2e..9b445ad 100644
--- a/app/delivery.py
+++ b/app/delivery.py
@@ -95,6 +95,12 @@ async def dispatch(feed: Feed, settings: Settings, msg: Message) -> DispatchResu
server = feed.ntfy_server.strip() or settings.default_ntfy_server
full_title = f"{msg.source}: {msg.title}" if msg.source else msg.title
+ # Per-feed auth wins; otherwise fall back to the default-server credentials.
+ has_feed_auth = bool(feed.ntfy_token.strip() or feed.ntfy_username.strip())
+ token = feed.ntfy_token if has_feed_auth else settings.default_ntfy_token
+ username = feed.ntfy_username if has_feed_auth else settings.default_ntfy_username
+ password = feed.ntfy_password if has_feed_auth else settings.default_ntfy_password
+
# --- ntfy (default channel; requires a topic) ---
if feed.ntfy_topic.strip():
try:
@@ -107,9 +113,9 @@ async def dispatch(feed: Feed, settings: Settings, msg: Message) -> DispatchResu
tags=feed.tags,
priority=feed.priority,
attach=msg.image if feed.attach_image else "",
- token=feed.ntfy_token,
- username=feed.ntfy_username,
- password=feed.ntfy_password,
+ token=token,
+ username=username,
+ password=password,
)
result.channels.append("ntfy")
except Exception as exc: # noqa: BLE001
@@ -146,6 +152,9 @@ async def send_admin_alert(settings: Settings, text: str) -> None:
message=text,
tags="warning",
priority=4,
+ token=settings.default_ntfy_token,
+ username=settings.default_ntfy_username,
+ password=settings.default_ntfy_password,
)
except Exception as exc: # noqa: BLE001
log.warning("admin alert failed: %s", exc)
diff --git a/app/main.py b/app/main.py
index 8ea7bf4..9de796f 100644
--- a/app/main.py
+++ b/app/main.py
@@ -384,6 +384,9 @@ def read_settings(session: Session = Depends(get_session), _: User = Depends(req
s = get_settings(session)
return {
"default_ntfy_server": s.default_ntfy_server,
+ "default_ntfy_token": s.default_ntfy_token,
+ "default_ntfy_username": s.default_ntfy_username,
+ "default_ntfy_password": s.default_ntfy_password,
"check_interval": s.check_interval,
"auth_enabled": s.auth_enabled,
"telegram_enabled": s.telegram_enabled,
@@ -410,6 +413,9 @@ def write_settings(
raise HTTPException(400, "Создайте хотя бы одного пользователя перед включением авторизации")
s.default_ntfy_server = data.default_ntfy_server.strip() or "https://ntfy.sh"
+ s.default_ntfy_token = data.default_ntfy_token.strip()
+ s.default_ntfy_username = data.default_ntfy_username.strip()
+ s.default_ntfy_password = data.default_ntfy_password
s.check_interval = data.check_interval
s.auth_enabled = data.auth_enabled
s.telegram_enabled = data.telegram_enabled
@@ -520,6 +526,8 @@ async def test_notification(
server = data.server.strip() or s.default_ntfy_server
if not data.topic.strip():
raise HTTPException(400, "Укажите тему")
+ # Use a custom server's own auth only if it matches the default; otherwise
+ # fall back to the configured default-server credentials.
try:
await ntfy.publish(
server=server,
@@ -528,6 +536,9 @@ async def test_notification(
message="Тестовое уведомление — всё работает!",
tags="white_check_mark",
priority=3,
+ token=s.default_ntfy_token,
+ username=s.default_ntfy_username,
+ password=s.default_ntfy_password,
)
except Exception as exc: # noqa: BLE001
raise HTTPException(502, f"Не удалось отправить: {exc}")
diff --git a/app/models.py b/app/models.py
index a9a221e..edec434 100644
--- a/app/models.py
+++ b/app/models.py
@@ -90,6 +90,11 @@ class Settings(SQLModel, table=True):
id: Optional[int] = Field(default=1, primary_key=True)
default_ntfy_server: str = "https://ntfy.sh"
+ # Default-server auth, used as a fallback for feeds without their own and
+ # for the "send test" action (for ntfy servers with access control).
+ default_ntfy_token: str = ""
+ default_ntfy_username: str = ""
+ default_ntfy_password: str = ""
check_interval: int = 5 # minutes (global default)
# Auth toggle (per-user credentials live in the User table).
diff --git a/app/schemas.py b/app/schemas.py
index bc3215b..5d51779 100644
--- a/app/schemas.py
+++ b/app/schemas.py
@@ -47,6 +47,9 @@ class FeedIn(BaseModel):
class SettingsIn(BaseModel):
default_ntfy_server: str = "https://ntfy.sh"
+ default_ntfy_token: str = ""
+ default_ntfy_username: str = ""
+ default_ntfy_password: str = ""
check_interval: int = 5
auth_enabled: bool = False
# Telegram
diff --git a/app/static/app.js b/app/static/app.js
index 68cce4b..51a2e40 100644
--- a/app/static/app.js
+++ b/app/static/app.js
@@ -410,6 +410,9 @@ sForm.addEventListener("submit", async e => {
e.preventDefault();
const payload = {
default_ntfy_server: sForm.default_ntfy_server.value.trim(),
+ default_ntfy_token: sForm.default_ntfy_token.value.trim(),
+ default_ntfy_username: sForm.default_ntfy_username.value.trim(),
+ default_ntfy_password: sForm.default_ntfy_password.value,
check_interval: parseInt(sForm.check_interval.value, 10),
auth_enabled: sForm.auth_enabled.checked,
telegram_enabled: sForm.telegram_enabled.checked,
diff --git a/app/static/i18n.js b/app/static/i18n.js
index 8b4b7c7..3384447 100644
--- a/app/static/i18n.js
+++ b/app/static/i18n.js
@@ -46,6 +46,8 @@ const I18N = {
"settings.ntfy": "ntfy",
"settings.defaultServer": "Сервер ntfy по умолчанию",
"settings.defaultServerHint": "Используется для лент, у которых не задан собственный сервер.",
+ "settings.ntfyAuth": "Авторизация на сервере ntfy",
+ "settings.ntfyAuthHint": "Нужно, если на сервере включён контроль доступа (ошибка 403 при отправке). Применяется к тесту, алертам и лентам без собственной авторизации.",
"settings.testPh": "тема для теста, напр. my-news",
"settings.testBtn": "Отправить тест",
"settings.check": "Проверка",
@@ -193,6 +195,8 @@ const I18N = {
"settings.ntfy": "ntfy",
"settings.defaultServer": "Default ntfy server",
"settings.defaultServerHint": "Used for feeds that don't define their own server.",
+ "settings.ntfyAuth": "ntfy server authentication",
+ "settings.ntfyAuthHint": "Needed if the server has access control enabled (403 on publish). Applies to the test, alerts and feeds without their own auth.",
"settings.testPh": "topic to test, e.g. my-news",
"settings.testBtn": "Send test",
"settings.check": "Polling",
diff --git a/app/templates/index.html b/app/templates/index.html
index ed3e0d6..fea2f7b 100644
--- a/app/templates/index.html
+++ b/app/templates/index.html
@@ -91,6 +91,18 @@
+ Авторизация на сервере ntfy
+
+