Repository: akvo/akvo-rsr

Issue:
Punctuation in Akvoapp RSR Pages URL creation
Context

Christien created a new Akvoapp for Footballforwater resulted in problems due to SSL cert not being valid.

https://f4winternational2.0.akvoapp.org/en/projects/

Problem or idea

A user creates a new Akvoapp RSR page which was based on a partner name including punctuation. '.' in this case as F4winternational2.0

Resulted in a URL that looked like:

https://f4winternational2.0.akvoapp.org/en/projects/ . this resulted in an untrusted domain.

The problem is that when a URL is generated, a '.' means that what is before is a subdomain of what comes after.

SSL certs are purchased/setup according to domains & subdomains. So we have SSL certs for *.akvoapp.org but not for *.*.akvapp.org

Solution or next step

Ensure that users are alerted/notified at text field that punctuation such as '.', ',', etc should not be used in naming.

OR

ensure that when generating a URl for akvoapp RSR pages, the system identifies punctuation and excludes it when naming the subdomain.


Discussion:

Resolving patch:
diff --git a/akvo/rsr/migrations/0125_auto_20180320_1252.py b/akvo/rsr/migrations/0125_auto_20180320_1252.py
new file mode 100644
--- /dev/null
+++ b/akvo/rsr/migrations/0125_auto_20180320_1252.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import akvo.rsr.validators
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('rsr', '0124_auto_20180309_0923'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='partnersite',
+            name='hostname',
+            field=models.CharField(help_text='<p>Your hostname is used in the default web address of your Akvo page. The web address created from  the hostname <em>myorganisation</em> would be <em>http://myorganisation.akvoapp.org/</em>.</p>', unique=True, max_length=50, verbose_name='hostname', validators=[akvo.rsr.validators.hostname_validator]),
+            preserve_default=True,
+        ),
+    ]
diff --git a/akvo/rsr/models/partner_site.py b/akvo/rsr/models/partner_site.py
--- a/akvo/rsr/models/partner_site.py
+++ b/akvo/rsr/models/partner_site.py
@@ -10,6 +10,7 @@
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
 
+from akvo.rsr.validators import hostname_validator
 from akvo.utils import rsr_show_keywords
 
 from ..fields import NullCharField, ValidXMLCharField, ValidXMLTextField
@@ -51,12 +52,12 @@ def show_keywords(self):
         'Organisation', verbose_name=_(u'organisation'),
         help_text=_('Select your organisation from the drop-down list.'))
     notes = ValidXMLTextField(verbose_name=_(u'Akvo page notes'), blank=True, default='')
-    hostname = ValidXMLCharField(
+    hostname = models.CharField(
         _(u'hostname'), max_length=50, unique=True, help_text=_(
             u'<p>Your hostname is used in the default web address of your Akvo page. '
             u'The web address created from  the hostname <em>myorganisation</em> would be '
             u'<em>http://myorganisation.akvoapp.org/</em>.</p>'
-        )
+        ), validators=[hostname_validator]
     )
     cname = NullCharField(
         _(u'CNAME'), max_length=100, unique=True, blank=True, null=True, help_text=_(
diff --git a/akvo/rsr/validators.py b/akvo/rsr/validators.py
--- a/akvo/rsr/validators.py
+++ b/akvo/rsr/validators.py
@@ -30,3 +30,11 @@ def string_validator(value):
     match = re.search(RESTRICTED_CHARACTERS, value)
     if match:
         raise ValidationError(match.group(0) + ' ' + _(u'is not an allowed character'))
+
+
+def hostname_validator(value):
+    if re.search(u'[^a-zA-Z0-9-]', value) is not None or value[0] == '-' or value[-1] == '-':
+        # https://tools.ietf.org/html/rfc1035
+        raise ValidationError(
+            'Only alpha numeric characters and hyphen are allowed. '
+            'Hostnames cannot start or end with a hyphen')


Test patch:
diff --git a/akvo/rsr/tests/test_validators.py b/akvo/rsr/tests/test_validators.py
new file mode 100644
--- /dev/null
+++ b/akvo/rsr/tests/test_validators.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# Akvo RSR is covered by the GNU Affero General Public License.
+# See more details in the license.txt file located at the root folder of the Akvo RSR module.
+# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
+
+from django.core.exceptions import ValidationError
+from django.test import TestCase
+
+from akvo.rsr.validators import hostname_validator
+
+INVALID_HOSTNAMES = [
+    '-9gag',
+    '9gag-',
+    '9.gag',
+    '9,gag',
+]
+
+
+VALID_HOSTNAMES = [
+    '9gag',
+    '9-gag',
+    'gag9',
+    'www',
+    '999',
+]
+
+
+class ValidatorTestCase(TestCase):
+    """Testing that validators work correctly."""
+
+    def test_invalid_hostnames_should_raise_error(self):
+        for hostname in INVALID_HOSTNAMES:
+            with self.assertRaises(ValidationError):
+                hostname_validator(hostname)
+
+    def test_valid_hostnames_should_get_validated(self):
+        for hostname in VALID_HOSTNAMES:
+            hostname_validator(hostname)