fix: allow ports for domains (#3171)

This commit is contained in:
Vlad Stan 2025-05-26 11:35:02 +03:00 committed by GitHub
parent 5345ccaf4e
commit 375b95c004
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 102 additions and 8 deletions

View File

@ -11,6 +11,7 @@ import jinja2
import jwt
import shortuuid
from fastapi.routing import APIRoute
from loguru import logger
from packaging import version
from pydantic.schema import field_schema
@ -279,12 +280,21 @@ def is_lnbits_version_ok(
def check_callback_url(url: str):
netloc = urlparse(url).netloc
if not settings.lnbits_callback_url_rules:
# no rules, all urls are allowed
return
u = urlparse(url)
for rule in settings.lnbits_callback_url_rules:
if re.match(rule, netloc) is None:
raise ValueError(
f"Callback not allowed. URL: {url}. Netloc: {netloc}. Rule: {rule}"
)
try:
if re.match(rule, f"{u.scheme}://{u.netloc}") is not None:
return
except re.error:
logger.debug(f"Invalid regex rule: '{rule}'. ")
continue
raise ValueError(
f"Callback not allowed. URL: {url}. Netloc: {u.netloc}. "
f"Please check your admin settings."
)
def download_url(url, save_path):

View File

@ -381,7 +381,7 @@ class SecuritySettings(LNbitsSettings):
lnbits_allowed_ips: list[str] = Field(default=[])
lnbits_blocked_ips: list[str] = Field(default=[])
lnbits_callback_url_rules: list[str] = Field(
default=["^(?!\\d+\\.\\d+\\.\\d+\\.\\d+$)(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}$"]
default=["https?://([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})(:\\d+)?"]
)
lnbits_wallet_limit_max_balance: int = Field(default=0, ge=0)

File diff suppressed because one or more lines are too long

View File

@ -278,7 +278,7 @@ window.localisation.en = {
callback_url_rules: 'Callback URL Rules',
enter_callback_url_rule: 'Enter URL rule as regex and hit enter',
callback_url_rule_hint:
'Callback URLs (like LNURL one) will be validated against all of these rules. No rule means all URLs are allowed.',
'Callback URLs (like LNURL one) will be validated against these rules. At leat one rule must match. No rule means all URLs are allowed.',
wallet_limiter: 'Wallet Limiter',
wallet_config: 'Wallet Config',
wallet_charts: 'Wallet Charts',

View File

@ -0,0 +1,84 @@
import pytest
from lnbits.helpers import check_callback_url
from lnbits.settings import Settings
@pytest.mark.anyio
def test_check_callback_url_not_allowed(settings: Settings):
settings.lnbits_callback_url_rules = [
"https?://([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})(:\\d+)?"
]
with pytest.raises(ValueError, match="Callback not allowed. URL: xx. Netloc: ."):
check_callback_url("xx")
with pytest.raises(
ValueError,
match="Callback not allowed. URL: http://localhost:3000/callback. "
"Netloc: localhost:3000. Please check your admin settings.",
):
check_callback_url("http://localhost:3000/callback")
with pytest.raises(
ValueError,
match="Callback not allowed. URL: https://localhost:3000/callback. "
"Netloc: localhost:3000. Please check your admin settings.",
):
check_callback_url("https://localhost:3000/callback")
with pytest.raises(
ValueError,
match="Callback not allowed. URL: http://192.168.2.2:3000/callback. "
"Netloc: 192.168.2.2:3000. Please check your admin settings.",
):
check_callback_url("http://192.168.2.2:3000/callback")
@pytest.mark.anyio
def test_check_callback_url_no_rules(settings: Settings):
settings.lnbits_callback_url_rules = [
"https?://([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})(:\\d+)?"
]
settings.lnbits_callback_url_rules.append(".*")
check_callback_url("xyz")
@pytest.mark.anyio
def test_check_callback_url_allow_all(settings: Settings):
settings.lnbits_callback_url_rules = []
check_callback_url("xyz")
@pytest.mark.anyio
def test_check_callback_url_allowed(settings: Settings):
settings.lnbits_callback_url_rules = [
"https?://([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})(:\\d+)?"
]
check_callback_url("http://google.com/callback")
check_callback_url("http://google.com:80/callback")
check_callback_url("http://google.com:8080/callback")
check_callback_url("https://google.com/callback")
check_callback_url("https://google.com:443/callback")
@pytest.mark.anyio
def test_check_callback_url_multiple_rules(settings: Settings):
with pytest.raises(
ValueError,
match="Callback not allowed. URL: http://localhost:3000/callback. "
"Netloc: localhost:3000. Please check your admin settings.",
):
check_callback_url("http://localhost:3000/callback")
settings.lnbits_callback_url_rules.append("http://localhost:3000")
check_callback_url("http://localhost:3000/callback") # should not raise
with pytest.raises(
ValueError,
match="Callback not allowed. URL: https://localhost:3000/callback. "
"Netloc: localhost:3000. Please check your admin settings.",
):
check_callback_url("https://localhost:3000/callback")
settings.lnbits_callback_url_rules.append("https://localhost:3000")
check_callback_url("https://localhost:3000/callback") # should not raise