mirror of
https://github.com/zulip/zulip.git
synced 2026-06-24 21:08:25 +08:00
realm creation flow: Restrict subdomains one can create via the web flow.
Disallow Realm.string_id's like "streams", "about", and several hundred others. Also restrict string_id's to be at least 3 characters long, and only use characters in [a-z0-9-]. Does not restrict realms created by the create_realm.py management command.
This commit is contained in:
parent
c6ceae868b
commit
2033381d24
@ -11,9 +11,11 @@ from jinja2 import Markup as mark_safe
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from zerver.models import get_realm_by_string_id
|
||||
from zerver.lib.name_restrictions import is_reserved_subdomain
|
||||
from zerver.lib.utils import get_subdomain, check_subdomain
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from zerver.models import Realm, get_user_profile_by_email, UserProfile, \
|
||||
completely_open, resolve_email_to_domain, get_realm, \
|
||||
@ -26,13 +28,6 @@ from six import text_type
|
||||
SIGNUP_STRING = u'Your e-mail does not match any existing open organization. ' + \
|
||||
u'Use a different e-mail address, or contact %s with questions.' % (settings.ZULIP_ADMINISTRATOR,)
|
||||
|
||||
def subdomain_unavailable(subdomain):
|
||||
# type: (text_type) -> text_type
|
||||
if settings.REALMS_HAVE_SUBDOMAINS:
|
||||
return _("The subdomain '%s' is not available. Please choose another one.") % (subdomain,)
|
||||
else:
|
||||
return _("The short name '%s' is not available. Please choose another one.") % (subdomain,)
|
||||
|
||||
if settings.SHOW_OSS_ANNOUNCEMENT:
|
||||
SIGNUP_STRING = u'Your e-mail does not match any existing organization. <br />' + \
|
||||
u"The zulip.com service is not taking new customer teams. <br /> " + \
|
||||
@ -96,11 +91,31 @@ class RegistrationForm(forms.Form):
|
||||
|
||||
def clean_realm_subdomain(self):
|
||||
# type: () -> str
|
||||
data = self.cleaned_data['realm_subdomain']
|
||||
realm = get_realm_by_string_id(data)
|
||||
if realm is not None:
|
||||
raise ValidationError(subdomain_unavailable(data))
|
||||
return data
|
||||
if settings.REALMS_HAVE_SUBDOMAINS:
|
||||
error_strings = {
|
||||
'too short': _("Subdomain needs to have length 3 or greater."),
|
||||
'extremal dash': _("Subdomain cannot start or end with a '-'."),
|
||||
'bad character': _("Subdomain can only have lowercase letters, numbers, and '-'s."),
|
||||
'unavailable': _("Subdomain unavailable. Please choose a different one.")}
|
||||
else:
|
||||
error_strings = {
|
||||
'too short': _("Short name needs at least 3 characters."),
|
||||
'extremal dash': _("Short name cannot start or end with a '-'."),
|
||||
'bad character': _("Short name can only have lowercase letters, numbers, and '-'s."),
|
||||
'unavailable': _("Short name unavailable. Please choose a different one.")}
|
||||
subdomain = self.cleaned_data['realm_subdomain']
|
||||
if not subdomain:
|
||||
return ''
|
||||
if len(subdomain) < 3:
|
||||
raise ValidationError(error_strings['too short'])
|
||||
if subdomain[0] == '-' or subdomain[-1] == '-':
|
||||
raise ValidationError(error_strings['extremal dash'])
|
||||
if not re.match('^[a-z0-9-]*$', subdomain):
|
||||
raise ValidationError(error_strings['bad character'])
|
||||
if is_reserved_subdomain(subdomain) or \
|
||||
get_realm_by_string_id(subdomain) is not None:
|
||||
raise ValidationError(error_strings['unavailable'])
|
||||
return subdomain
|
||||
|
||||
class ToSForm(forms.Form):
|
||||
terms = forms.BooleanField(required=True)
|
||||
|
||||
62
zerver/lib/name_restrictions.py
Normal file
62
zerver/lib/name_restrictions.py
Normal file
@ -0,0 +1,62 @@
|
||||
from six import text_type
|
||||
|
||||
def is_reserved_subdomain(subdomain):
|
||||
# type: (text_type) -> bool
|
||||
if subdomain in ZULIP_RESERVED_SUBDOMAINS:
|
||||
return True
|
||||
if subdomain[-1] == 's' and subdomain[:-1] in ZULIP_RESERVED_SUBDOMAINS:
|
||||
return True
|
||||
if subdomain in GENERIC_RESERVED_SUBDOMAINS:
|
||||
return True
|
||||
if subdomain[-1] == 's' and subdomain[:-1] in GENERIC_RESERVED_SUBDOMAINS:
|
||||
return True
|
||||
return False
|
||||
|
||||
ZULIP_RESERVED_SUBDOMAINS = frozenset([
|
||||
'stream', 'channel', 'topic', 'thread', 'installation', 'organization', 'realm',
|
||||
'team', 'subdomain', 'activity', 'octopus', 'acme'
|
||||
'zulipdev', 'localhost', 'staging', 'prod', 'production', 'testing', 'nagios', 'nginx',
|
||||
'server', 'client', 'features', 'integration', 'bot', 'blog', 'history', 'story',
|
||||
'stories', 'testimonial', 'compare',
|
||||
'slack', 'mattermost', 'rocketchat', 'irc', 'twitter', 'zephyr',
|
||||
'zulip', 'tulip', 'humbug',
|
||||
'plan9', 'electron', 'linux', 'mac', 'windows', 'cli', 'ubuntu', 'android', 'ios',
|
||||
'contribute', 'floss', 'foss', 'free', 'opensource', 'open', 'code',
|
||||
'intern', 'outreachy', 'gsoc', 'gci'])
|
||||
|
||||
# Most of this list was curated from the following sources:
|
||||
# http://wiki.dwscoalition.org/notes/List_of_reserved_subdomains (license: CC-BY-SA 3.0)
|
||||
# http://stackoverflow.com/questions/11868191/which-saas-subdomains-to-block (license: CC-BY-SA 2.5)
|
||||
GENERIC_RESERVED_SUBDOMAINS = frozenset([
|
||||
'about', 'abuse', 'account', 'ad', 'admanager', 'admin', 'admindashboard',
|
||||
'administrator', 'adsense', 'adword', 'affiliate', 'alpha', 'anonymous',
|
||||
'api', 'assets', 'audio', 'badges', 'beta', 'billing', 'biz', 'blog',
|
||||
'board', 'bookmark', 'bot', 'bugs', 'buy', 'cache', 'calendar', 'chat',
|
||||
'clients', 'cname', 'code', 'comment', 'communities', 'community',
|
||||
'contact', 'contributor', 'control', 'coppa', 'copyright', 'cpanel', 'css',
|
||||
'cssproxy', 'customise', 'customize', 'dashboard', 'data', 'demo', 'deploy',
|
||||
'deployment', 'desktop', 'dev', 'devel', 'developer', 'development',
|
||||
'discussion', 'diversity', 'dmca', 'docs', 'donate', 'download', 'e-mail',
|
||||
'email', 'embed', 'embedded', 'example', 'explore', 'faq', 'favorite',
|
||||
'favourites', 'features', 'feed', 'feedback', 'files', 'forum', 'friend',
|
||||
'ftp', 'general', 'gettingstarted', 'gift', 'git', 'global', 'graphs',
|
||||
'guide', 'hack', 'help', 'home', 'hostmaster', 'https', 'icon', 'im',
|
||||
'image', 'img', 'inbox', 'index', 'investors', 'invite', 'invoice', 'ios',
|
||||
'ipad', 'iphone', 'irc', 'jabber', 'jars', 'jobs', 'join', 'js', 'kb',
|
||||
'knowledgebase', 'launchpad', 'legal', 'livejournal', 'lj', 'login', 'logs',
|
||||
'm', 'mail', 'main', 'manage', 'map', 'media', 'memories', 'memory',
|
||||
'merchandise', 'messages', 'mobile', 'my', 'mystore', 'networks', 'new',
|
||||
'newsite', 'official', 'ogg', 'online', 'order', 'paid', 'panel', 'partner',
|
||||
'partnerpage', 'pay', 'payment', 'picture', 'policy', 'pop', 'popular',
|
||||
'portal', 'post', 'postmaster', 'press', 'pricing', 'principles', 'privacy',
|
||||
'private', 'profile', 'public', 'random', 'redirect', 'register',
|
||||
'registration', 'resolver', 'root', 'rss', 's', 'sandbox', 'school',
|
||||
'search', 'secure', 'servers', 'service', 'setting', 'shop', 'shortcuts',
|
||||
'signin', 'signup', 'sitemap', 'sitenews', 'sites', 'sms', 'smtp', 'sorry',
|
||||
'ssl', 'staff', 'stage', 'staging', 'stars', 'stat', 'static', 'statistics',
|
||||
'status', 'store', 'style', 'support', 'surveys', 'svn', 'syn',
|
||||
'syndicated', 'system', 'tag', 'talk', 'team', 'termsofservice', 'test',
|
||||
'testers', 'ticket', 'tool', 'tos', 'trac', 'translate', 'update',
|
||||
'upgrade', 'uploads', 'use', 'user', 'username', 'validation', 'videos',
|
||||
'volunteer', 'web', 'webdisk', 'webmail', 'webmaster', 'whm', 'whois',
|
||||
'wiki', 'www', 'www0', 'www8', 'www9', 'xml', 'xmpp', 'xoxo'])
|
||||
@ -606,7 +606,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||
# type: () -> None
|
||||
username = "user1"
|
||||
password = "test"
|
||||
string_id = "test"
|
||||
string_id = "zuliptest"
|
||||
domain = "test.com"
|
||||
email = "user1@test.com"
|
||||
|
||||
@ -648,7 +648,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||
# type: () -> None
|
||||
username = "user1"
|
||||
password = "test"
|
||||
string_id = "testid"
|
||||
string_id = "zuliptest"
|
||||
domain = "test.com"
|
||||
email = "user1@test.com"
|
||||
realm_name = "Test"
|
||||
@ -686,6 +686,41 @@ class RealmCreationTest(ZulipTestCase):
|
||||
self.assertEqual(realm.name, realm_name)
|
||||
self.assertEqual(realm.subdomain, string_id)
|
||||
|
||||
def test_subdomain_restrictions(self):
|
||||
# type: () -> None
|
||||
username = "user1"
|
||||
password = "test"
|
||||
domain = "test.com"
|
||||
email = "user1@test.com"
|
||||
realm_name = "Test"
|
||||
|
||||
with self.settings(REALMS_HAVE_SUBDOMAINS=False), self.settings(OPEN_REALM_CREATION=True):
|
||||
result = self.client_post('/create_realm/', {'email': email})
|
||||
self.client_get(result["Location"])
|
||||
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
||||
self.client_get(confirmation_url)
|
||||
|
||||
errors = {'id': "at least 3 characters",
|
||||
'-id': "cannot start or end with a",
|
||||
'string-ID': "lowercase letters",
|
||||
'string_id': "lowercase letters",
|
||||
'stream': "unavailable",
|
||||
'streams': "unavailable",
|
||||
'about': "unavailable",
|
||||
'abouts': "unavailable",
|
||||
'mit': "unavailable"}
|
||||
for string_id, error_msg in errors.items():
|
||||
result = self.submit_reg_form_for_user(username, password, domain = domain,
|
||||
realm_subdomain = string_id,
|
||||
realm_name = realm_name)
|
||||
self.assert_in_response(error_msg, result)
|
||||
|
||||
# test valid subdomain
|
||||
result = self.submit_reg_form_for_user(username, password, domain = domain,
|
||||
realm_subdomain = 'a-0',
|
||||
realm_name = realm_name)
|
||||
self.assertEquals(result.status_code, 302)
|
||||
|
||||
class UserSignUpTest(ZulipTestCase):
|
||||
|
||||
def test_user_default_language(self):
|
||||
@ -957,7 +992,7 @@ class UserSignUpTest(ZulipTestCase):
|
||||
password = "test"
|
||||
domain = "mit.edu"
|
||||
email = "sipbtest@mit.edu"
|
||||
subdomain = "cs"
|
||||
subdomain = "sipb"
|
||||
realm_name = "MIT"
|
||||
|
||||
user_profile = get_user_profile_by_email(email)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user