coturn: Validate TURN URIs if provided in form

Signed-off-by: James Valleroy <jvalleroy@mailbox.org>

- Re-use the same validator in Matrix Synapse.
- Avoid importing plinth classes in actions files.
Signed-off-by: Joseph Nuthalapati <njoseph@riseup.net>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
James Valleroy 2021-04-13 21:48:03 -04:00
parent 7a30470cb5
commit 9b446d5dd1
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
5 changed files with 25 additions and 4 deletions

View File

@ -30,6 +30,8 @@ yaml = YAML()
yaml.allow_duplicate_keys = True yaml.allow_duplicate_keys = True
yaml.preserve_quotes = True yaml.preserve_quotes = True
TURN_URI_REGEX = r'(stun|turn):(.*):([0-9]{4})\?transport=(tcp|udp)'
def parse_arguments(): def parse_arguments():
"""Return parsed command line arguments as dictionary""" """Return parsed command line arguments as dictionary"""
@ -303,7 +305,7 @@ def subcommand_mam(argument):
def _generate_service(uri: str) -> dict: def _generate_service(uri: str) -> dict:
"""Generate ejabberd mod_stun_disco service config from Coturn URI.""" """Generate ejabberd mod_stun_disco service config from Coturn URI."""
pattern = re.compile(r'(stun|turn):(.*):([0-9]{4})\?transport=(tcp|udp)') pattern = re.compile(TURN_URI_REGEX)
typ, domain, port, transport = pattern.match(uri).groups() typ, domain, port, transport = pattern.match(uri).groups()
return { return {
"host": domain, "host": domain,

View File

@ -5,10 +5,13 @@
from __future__ import annotations # Can be removed in Python 3.10 from __future__ import annotations # Can be removed in Python 3.10
import json import json
import re
from dataclasses import dataclass, field from dataclasses import dataclass, field
from plinth import app from plinth import app
TURN_URI_REGEX = r'(stun|turn):(.*):([0-9]{4})\?transport=(tcp|udp)'
@dataclass @dataclass
class TurnConfiguration: class TurnConfiguration:
@ -45,6 +48,12 @@ class TurnConfiguration:
'shared_secret': self.shared_secret 'shared_secret': self.shared_secret
}) })
@staticmethod
def validate_turn_uris(turn_uris: list[str]) -> bool:
"""Return whether the given TURN URI is valid."""
pattern = re.compile(TURN_URI_REGEX)
return all(map(pattern.match, turn_uris))
class TurnConsumer(app.FollowerComponent): class TurnConsumer(app.FollowerComponent):
"""Component to manage coturn configuration. """Component to manage coturn configuration.

View File

@ -4,9 +4,11 @@ Forms for Coturn app.
""" """
from django import forms from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from plinth.modules import coturn from plinth.modules import coturn
from plinth.modules.coturn.components import TurnConfiguration
def get_domain_choices(): def get_domain_choices():
@ -14,6 +16,12 @@ def get_domain_choices():
return ((domain, domain) for domain in coturn.get_available_domains()) return ((domain, domain) for domain in coturn.get_available_domains())
def turn_uris_validator(turn_uris):
"""Validate list of STUN/TURN Server URIs."""
if not TurnConfiguration.validate_turn_uris(turn_uris.split("\n")):
raise ValidationError(_('Invalid list of STUN/TURN Server URIs'))
class CoturnForm(forms.Form): class CoturnForm(forms.Form):
"""Form to select a TLS domain for Coturn.""" """Form to select a TLS domain for Coturn."""

View File

@ -8,6 +8,7 @@ from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from plinth import cfg from plinth import cfg
from plinth.modules.coturn.forms import turn_uris_validator
from plinth.utils import format_lazy from plinth.utils import format_lazy
@ -35,7 +36,7 @@ class EjabberdForm(forms.Form):
label=_('STUN/TURN Server URIs'), required=False, strip=True, label=_('STUN/TURN Server URIs'), required=False, strip=True,
widget=forms.Textarea(attrs={'rows': 4}), widget=forms.Textarea(attrs={'rows': 4}),
help_text=_('List of public URIs of the STUN/TURN server, one on each ' help_text=_('List of public URIs of the STUN/TURN server, one on each '
'line.')) 'line.'), validators=[turn_uris_validator])
shared_secret = forms.CharField( shared_secret = forms.CharField(
label=_('Shared Authentication Secret'), required=False, strip=True, label=_('Shared Authentication Secret'), required=False, strip=True,

View File

@ -5,8 +5,9 @@ Forms for the Matrix Synapse module.
from django import forms from django import forms
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from plinth.modules.coturn.forms import turn_uris_validator
from django.utils.translation import ugettext_lazy as _
from plinth.utils import format_lazy from plinth.utils import format_lazy
@ -30,7 +31,7 @@ class MatrixSynapseForm(forms.Form):
label=_('STUN/TURN Server URIs'), required=False, strip=True, label=_('STUN/TURN Server URIs'), required=False, strip=True,
widget=forms.Textarea(attrs={'rows': 4}), widget=forms.Textarea(attrs={'rows': 4}),
help_text=_('List of public URIs of the STUN/TURN server, one on each ' help_text=_('List of public URIs of the STUN/TURN server, one on each '
'line.')) 'line.'), validators=[turn_uris_validator])
shared_secret = forms.CharField( shared_secret = forms.CharField(
label=_('Shared Authentication Secret'), required=False, strip=True, label=_('Shared Authentication Secret'), required=False, strip=True,