Repository: weni-ai/bothub-engine

Issue:
Duplicated nicknames
Duplicated nicknames are enabled but it's not supposed to be, it's a security issue.


Discussion:
User's nickname field must be unique
https://github.com/push-flow/bothub/blob/master/bothub/authentication/models.py#L66

Resolving patch:
diff --git a/bothub/authentication/migrations/0004_auto_20180605_1357.py b/bothub/authentication/migrations/0004_auto_20180605_1357.py
new file mode 100644
--- /dev/null
+++ b/bothub/authentication/migrations/0004_auto_20180605_1357.py
@@ -0,0 +1,20 @@
+# Generated by Django 2.0.2 on 2018-06-05 13:57
+
+import django.core.validators
+from django.db import migrations, models
+import re
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('authentication', '0003_auto_20180522_1705'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='user',
+            name='nickname',
+            field=models.CharField(help_text="User's nickname, using letters, numbers, underscores and hyphens without spaces.", max_length=16, unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'nickname' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='nickname'),
+        ),
+    ]
diff --git a/bothub/authentication/models.py b/bothub/authentication/models.py
--- a/bothub/authentication/models.py
+++ b/bothub/authentication/models.py
@@ -68,7 +68,8 @@ class Meta:
         max_length=16,
         validators=[validate_user_nickname],
         help_text=_('User\'s nickname, using letters, numbers, underscores ' +
-                    'and hyphens without spaces.'))
+                    'and hyphens without spaces.'),
+        unique=True)
     locale = models.CharField(
         _('locale'),
         max_length=48,


Test patch:
diff --git a/bothub/api/tests/user.py b/bothub/api/tests/user.py
--- a/bothub/api/tests/user.py
+++ b/bothub/api/tests/user.py
@@ -60,6 +60,22 @@ def test_invalid_password(self):
             'password',
             content_data.keys())
 
+    def test_unique_nickname(self):
+        nickname = 'fake'
+        User.objects.create_user('user1@user.com', nickname)
+        response, content_data = self.request({
+            'email': 'user2@user.com',
+            'name': 'Fake',
+            'nickname': nickname,
+            'password': 'abc!1234',
+        })
+        self.assertEqual(
+            response.status_code,
+            status.HTTP_400_BAD_REQUEST)
+        self.assertIn(
+            'nickname',
+            content_data.keys())
+
 
 class UserUpdateTestCase(TestCase):
     def setUp(self):
diff --git a/bothub/authentication/tests.py b/bothub/authentication/tests.py
--- a/bothub/authentication/tests.py
+++ b/bothub/authentication/tests.py
@@ -1,4 +1,5 @@
 from django.test import TestCase
+from django.db import IntegrityError
 
 from .models import User
 
@@ -24,3 +25,8 @@ def test_new_superuser_fail_issuperuser_false(self):
                 'fake@user.com',
                 'fake',
                 is_superuser=False)
+
+    def test_user_unique_nickname(self):
+        User.objects.create_user('user1@user.com', 'fake')
+        with self.assertRaises(IntegrityError):
+            User.objects.create_user('user2@user.com', 'fake')
diff --git a/bothub/common/tests.py b/bothub/common/tests.py
--- a/bothub/common/tests.py
+++ b/bothub/common/tests.py
@@ -258,7 +258,7 @@ def test_does_not_have_translation(self):
 
 class RepositoryTestCase(TestCase):
     def setUp(self):
-        self.owner = User.objects.create_user('owner@user.com', 'user')
+        self.owner = User.objects.create_user('owner@user.com', 'owner')
         self.user = User.objects.create_user('fake@user.com', 'user')
 
         self.repository = Repository.objects.create(
@@ -354,7 +354,7 @@ def teste_delete(self):
 
 class RepositoryAuthorizationTestCase(TestCase):
     def setUp(self):
-        self.owner = User.objects.create_user('owner@user.com', 'user')
+        self.owner = User.objects.create_user('owner@user.com', 'owner')
         self.user = User.objects.create_user('fake@user.com', 'user')
 
         self.repository = Repository.objects.create(