Mercurial > kallithea
comparison rhodecode/model/validators.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl
Imported some of the GPLv3'd changes from RhodeCode v2.2.5.
This imports changes between changesets 21af6c4eab3d and 6177597791c2 in
RhodeCode's original repository, including only changes to Python files and HTML.
RhodeCode clearly licensed its changes to these files under GPLv3
in their /LICENSE file, which states the following:
The Python code and integrated HTML are licensed under the GPLv3 license.
(See:
https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE
or
http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE
for an online copy of that LICENSE file)
Conservancy reviewed these changes and confirmed that they can be licensed as
a whole to the Kallithea project under GPLv3-only.
While some of the contents committed herein are clearly licensed
GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the
statement above from RhodeCode indicates that they intend GPLv3-only as their
license, per GPLv3ยง14 and other relevant sections of GPLv3.
author | Bradley M. Kuhn <bkuhn@sfconservancy.org> |
---|---|
date | Wed, 02 Jul 2014 19:03:13 -0400 |
parents | 5293d4bbb1ea |
children | 7e5f8c12a3fc |
comparison
equal
deleted
inserted
replaced
4115:8b7294a804a0 | 4116:ffd45b185016 |
---|---|
1 # -*- coding: utf-8 -*- | |
2 # This program is free software: you can redistribute it and/or modify | |
3 # it under the terms of the GNU General Public License as published by | |
4 # the Free Software Foundation, either version 3 of the License, or | |
5 # (at your option) any later version. | |
6 # | |
7 # This program is distributed in the hope that it will be useful, | |
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 # GNU General Public License for more details. | |
11 # | |
12 # You should have received a copy of the GNU General Public License | |
13 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
1 """ | 14 """ |
2 Set of generic validators | 15 Set of generic validators |
3 """ | 16 """ |
17 | |
4 import os | 18 import os |
5 import re | 19 import re |
6 import formencode | 20 import formencode |
7 import logging | 21 import logging |
8 from collections import defaultdict | 22 from collections import defaultdict |
14 NotEmpty, IPAddress, CIDR, String, FancyValidator | 28 NotEmpty, IPAddress, CIDR, String, FancyValidator |
15 ) | 29 ) |
16 from rhodecode.lib.compat import OrderedSet | 30 from rhodecode.lib.compat import OrderedSet |
17 from rhodecode.lib import ipaddr | 31 from rhodecode.lib import ipaddr |
18 from rhodecode.lib.utils import repo_name_slug | 32 from rhodecode.lib.utils import repo_name_slug |
19 from rhodecode.lib.utils2 import safe_int, str2bool | 33 from rhodecode.lib.utils2 import safe_int, str2bool, aslist |
20 from rhodecode.model.db import RepoGroup, Repository, UserGroup, User,\ | 34 from rhodecode.model.db import RepoGroup, Repository, UserGroup, User,\ |
21 ChangesetStatus | 35 ChangesetStatus |
22 from rhodecode.lib.exceptions import LdapImportError | 36 from rhodecode.lib.exceptions import LdapImportError |
23 from rhodecode.config.routing import ADMIN_PREFIX | 37 from rhodecode.config.routing import ADMIN_PREFIX |
24 from rhodecode.lib.auth import HasReposGroupPermissionAny, HasPermissionAny | 38 from rhodecode.lib.auth import HasRepoGroupPermissionAny, HasPermissionAny |
25 | 39 |
26 # silence warnings and pylint | 40 # silence warnings and pylint |
27 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \ | 41 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \ |
28 NotEmpty, IPAddress, CIDR, String, FancyValidator | 42 NotEmpty, IPAddress, CIDR, String, FancyValidator |
29 | 43 |
30 log = logging.getLogger(__name__) | 44 log = logging.getLogger(__name__) |
31 | 45 |
32 | 46 class _Missing(object): |
33 class UniqueList(formencode.FancyValidator): | 47 pass |
34 """ | 48 |
35 Unique List ! | 49 Missing = _Missing() |
36 """ | |
37 messages = dict( | |
38 empty=_('Value cannot be an empty list'), | |
39 missing_value=_('Value cannot be an empty list'), | |
40 ) | |
41 | |
42 def _to_python(self, value, state): | |
43 if isinstance(value, list): | |
44 return value | |
45 elif isinstance(value, set): | |
46 return list(value) | |
47 elif isinstance(value, tuple): | |
48 return list(value) | |
49 elif value is None: | |
50 return [] | |
51 else: | |
52 return [value] | |
53 | |
54 def empty_value(self, value): | |
55 return [] | |
56 | 50 |
57 | 51 |
58 class StateObj(object): | 52 class StateObj(object): |
59 """ | 53 """ |
60 this is needed to translate the messages using _() in validators | 54 this is needed to translate the messages using _() in validators |
77 state._ = staticmethod(_) | 71 state._ = staticmethod(_) |
78 #inject validator into state object | 72 #inject validator into state object |
79 return self.message(key, state, **kwargs) | 73 return self.message(key, state, **kwargs) |
80 | 74 |
81 | 75 |
76 def UniqueList(): | |
77 class _UniqueList(formencode.FancyValidator): | |
78 """ | |
79 Unique List ! | |
80 """ | |
81 messages = dict( | |
82 empty=_('Value cannot be an empty list'), | |
83 missing_value=_('Value cannot be an empty list'), | |
84 ) | |
85 | |
86 def _to_python(self, value, state): | |
87 def make_unique(value): | |
88 seen = [] | |
89 return [c for c in value if not (c in seen or seen.append(c))] | |
90 | |
91 if isinstance(value, list): | |
92 return make_unique(value) | |
93 elif isinstance(value, set): | |
94 return make_unique(list(value)) | |
95 elif isinstance(value, tuple): | |
96 return make_unique(list(value)) | |
97 elif value is None: | |
98 return [] | |
99 else: | |
100 return [value] | |
101 | |
102 def empty_value(self, value): | |
103 return [] | |
104 | |
105 return _UniqueList | |
106 | |
107 | |
108 def UniqueListFromString(): | |
109 class _UniqueListFromString(UniqueList()): | |
110 def _to_python(self, value, state): | |
111 if isinstance(value, basestring): | |
112 value = aslist(value, ',') | |
113 return super(_UniqueListFromString, self)._to_python(value, state) | |
114 return _UniqueListFromString | |
115 | |
116 | |
82 def ValidUsername(edit=False, old_data={}): | 117 def ValidUsername(edit=False, old_data={}): |
83 class _validator(formencode.validators.FancyValidator): | 118 class _validator(formencode.validators.FancyValidator): |
84 messages = { | 119 messages = { |
85 'username_exists': _(u'Username "%(username)s" already exists'), | 120 'username_exists': _(u'Username "%(username)s" already exists'), |
86 'system_invalid_username': | 121 'system_invalid_username': |
106 raise formencode.Invalid(msg, value, state) | 141 raise formencode.Invalid(msg, value, state) |
107 | 142 |
108 if re.match(r'^[a-zA-Z0-9\_]{1}[a-zA-Z0-9\-\_\.]*$', value) is None: | 143 if re.match(r'^[a-zA-Z0-9\_]{1}[a-zA-Z0-9\-\_\.]*$', value) is None: |
109 msg = M(self, 'invalid_username', state) | 144 msg = M(self, 'invalid_username', state) |
110 raise formencode.Invalid(msg, value, state) | 145 raise formencode.Invalid(msg, value, state) |
146 return _validator | |
147 | |
148 | |
149 def ValidRegex(msg=None): | |
150 class _validator(formencode.validators.Regex): | |
151 messages = dict(invalid=msg or _('The input is not valid')) | |
111 return _validator | 152 return _validator |
112 | 153 |
113 | 154 |
114 def ValidRepoUser(): | 155 def ValidRepoUser(): |
115 class _validator(formencode.validators.FancyValidator): | 156 class _validator(formencode.validators.FancyValidator): |
169 ) | 210 ) |
170 | 211 |
171 return _validator | 212 return _validator |
172 | 213 |
173 | 214 |
174 def ValidReposGroup(edit=False, old_data={}): | 215 def ValidRepoGroup(edit=False, old_data={}): |
175 class _validator(formencode.validators.FancyValidator): | 216 class _validator(formencode.validators.FancyValidator): |
176 messages = { | 217 messages = { |
177 'group_parent_id': _(u'Cannot assign this group as parent'), | 218 'group_parent_id': _(u'Cannot assign this group as parent'), |
178 'group_exists': _(u'Group "%(group_name)s" already exists'), | 219 'group_exists': _(u'Group "%(group_name)s" already exists'), |
179 'repo_exists': | 220 'repo_exists': |
245 msg = M(self, 'invalid_password', state) | 286 msg = M(self, 'invalid_password', state) |
246 raise formencode.Invalid(msg, value, state,) | 287 raise formencode.Invalid(msg, value, state,) |
247 return _validator | 288 return _validator |
248 | 289 |
249 | 290 |
250 def ValidPasswordsMatch(): | 291 def ValidOldPassword(username): |
292 class _validator(formencode.validators.FancyValidator): | |
293 messages = { | |
294 'invalid_password': _(u'Invalid old password') | |
295 } | |
296 | |
297 def validate_python(self, value, state): | |
298 from rhodecode.lib import auth_modules | |
299 if not auth_modules.authenticate(username, value, ''): | |
300 msg = M(self, 'invalid_password', state) | |
301 raise formencode.Invalid(msg, value, state, | |
302 error_dict=dict(current_password=msg) | |
303 ) | |
304 return _validator | |
305 | |
306 | |
307 def ValidPasswordsMatch(passwd='new_password', passwd_confirmation='password_confirmation'): | |
251 class _validator(formencode.validators.FancyValidator): | 308 class _validator(formencode.validators.FancyValidator): |
252 messages = { | 309 messages = { |
253 'password_mismatch': _(u'Passwords do not match'), | 310 'password_mismatch': _(u'Passwords do not match'), |
254 } | 311 } |
255 | 312 |
256 def validate_python(self, value, state): | 313 def validate_python(self, value, state): |
257 | 314 |
258 pass_val = value.get('password') or value.get('new_password') | 315 pass_val = value.get('password') or value.get(passwd) |
259 if pass_val != value['password_confirmation']: | 316 if pass_val != value[passwd_confirmation]: |
260 msg = M(self, 'password_mismatch', state) | 317 msg = M(self, 'password_mismatch', state) |
261 raise formencode.Invalid(msg, value, state, | 318 raise formencode.Invalid(msg, value, state, |
262 error_dict=dict(password_confirmation=msg) | 319 error_dict={passwd:msg, passwd_confirmation: msg} |
263 ) | 320 ) |
264 return _validator | 321 return _validator |
265 | 322 |
266 | 323 |
267 def ValidAuth(): | 324 def ValidAuth(): |
271 'invalid_username': _(u'invalid user name'), | 328 'invalid_username': _(u'invalid user name'), |
272 'disabled_account': _(u'Your account is disabled') | 329 'disabled_account': _(u'Your account is disabled') |
273 } | 330 } |
274 | 331 |
275 def validate_python(self, value, state): | 332 def validate_python(self, value, state): |
276 from rhodecode.lib.auth import authenticate | 333 from rhodecode.lib import auth_modules |
277 | 334 |
278 password = value['password'] | 335 password = value['password'] |
279 username = value['username'] | 336 username = value['username'] |
280 | 337 |
281 if not authenticate(username, password): | 338 if not auth_modules.authenticate(username, password): |
282 user = User.get_by_username(username) | 339 user = User.get_by_username(username) |
283 if user and not user.active: | 340 if user and not user.active: |
284 log.warning('user %s is disabled' % username) | 341 log.warning('user %s is disabled' % username) |
285 msg = M(self, 'disabled_account', state) | 342 msg = M(self, 'disabled_account', state) |
286 raise formencode.Invalid(msg, value, state, | 343 raise formencode.Invalid(msg, value, state, |
401 | 458 |
402 | 459 |
403 def ValidCloneUri(): | 460 def ValidCloneUri(): |
404 from rhodecode.lib.utils import make_ui | 461 from rhodecode.lib.utils import make_ui |
405 | 462 |
406 def url_handler(repo_type, url, ui=None): | 463 def url_handler(repo_type, url, ui): |
407 if repo_type == 'hg': | 464 if repo_type == 'hg': |
408 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository | 465 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository |
409 from rhodecode.lib.vcs.utils.hgcompat import httppeer | |
410 if url.startswith('http'): | 466 if url.startswith('http'): |
411 ## initially check if it's at least the proper URL | 467 # initially check if it's at least the proper URL |
412 ## or does it pass basic auth | 468 # or does it pass basic auth |
413 MercurialRepository._check_url(url) | 469 MercurialRepository._check_url(url, ui) |
414 httppeer(ui, url)._capabilities() | |
415 elif url.startswith('svn+http'): | 470 elif url.startswith('svn+http'): |
416 from hgsubversion.svnrepo import svnremoterepo | 471 from hgsubversion.svnrepo import svnremoterepo |
417 svnremoterepo(ui, url).capabilities | 472 svnremoterepo(ui, url).svn.uuid |
418 elif url.startswith('git+http'): | 473 elif url.startswith('git+http'): |
419 raise NotImplementedError() | 474 raise NotImplementedError() |
420 else: | 475 else: |
421 raise Exception('clone from URI %s not allowed' % (url,)) | 476 raise Exception('clone from URI %s not allowed' % (url,)) |
422 | 477 |
423 elif repo_type == 'git': | 478 elif repo_type == 'git': |
424 from rhodecode.lib.vcs.backends.git.repository import GitRepository | 479 from rhodecode.lib.vcs.backends.git.repository import GitRepository |
425 if url.startswith('http'): | 480 if url.startswith('http'): |
426 ## initially check if it's at least the proper URL | 481 # initially check if it's at least the proper URL |
427 ## or does it pass basic auth | 482 # or does it pass basic auth |
428 GitRepository._check_url(url) | 483 GitRepository._check_url(url) |
429 elif url.startswith('svn+http'): | 484 elif url.startswith('svn+http'): |
430 raise NotImplementedError() | 485 raise NotImplementedError() |
431 elif url.startswith('hg+http'): | 486 elif url.startswith('hg+http'): |
432 raise NotImplementedError() | 487 raise NotImplementedError() |
489 return value | 544 return value |
490 | 545 |
491 def validate_python(self, value, state): | 546 def validate_python(self, value, state): |
492 gr = RepoGroup.get(value) | 547 gr = RepoGroup.get(value) |
493 gr_name = gr.group_name if gr else None # None means ROOT location | 548 gr_name = gr.group_name if gr else None # None means ROOT location |
494 val = HasReposGroupPermissionAny('group.write', 'group.admin') | 549 # create repositories with write permission on group is set to true |
550 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')() | |
551 group_admin = HasRepoGroupPermissionAny('group.admin')(gr_name, | |
552 'can write into group validator') | |
553 group_write = HasRepoGroupPermissionAny('group.write')(gr_name, | |
554 'can write into group validator') | |
555 forbidden = not (group_admin or (group_write and create_on_write)) | |
495 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository') | 556 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository') |
496 forbidden = not val(gr_name, 'can write into group validator') | 557 gid = (old_data['repo_group'].get('group_id') |
497 value_changed = True # old_data['repo_group'].get('group_id') != safe_int(value) | 558 if (old_data and 'repo_group' in old_data) else None) |
498 if value_changed: # do check if we changed the value | 559 value_changed = gid != safe_int(value) |
560 new = not old_data | |
561 # do check if we changed the value, there's a case that someone got | |
562 # revoked write permissions to a repository, he still created, we | |
563 # don't need to check permission if he didn't change the value of | |
564 # groups in form box | |
565 if value_changed or new: | |
499 #parent group need to be existing | 566 #parent group need to be existing |
500 if gr and forbidden: | 567 if gr and forbidden: |
501 msg = M(self, 'permission_denied', state) | 568 msg = M(self, 'permission_denied', state) |
502 raise formencode.Invalid(msg, value, state, | 569 raise formencode.Invalid(msg, value, state, |
503 error_dict=dict(repo_type=msg) | 570 error_dict=dict(repo_type=msg) |
532 if can_create_in_root and gr is None: | 599 if can_create_in_root and gr is None: |
533 #we can create in root, we're fine no validations required | 600 #we can create in root, we're fine no validations required |
534 return | 601 return |
535 | 602 |
536 forbidden_in_root = gr is None and not can_create_in_root | 603 forbidden_in_root = gr is None and not can_create_in_root |
537 val = HasReposGroupPermissionAny('group.admin') | 604 val = HasRepoGroupPermissionAny('group.admin') |
538 forbidden = not val(gr_name, 'can create group validator') | 605 forbidden = not val(gr_name, 'can create group validator') |
539 if forbidden_in_root or forbidden: | 606 if forbidden_in_root or forbidden: |
540 msg = M(self, 'permission_denied', state) | 607 msg = M(self, 'permission_denied', state) |
541 raise formencode.Invalid(msg, value, state, | 608 raise formencode.Invalid(msg, value, state, |
542 error_dict=dict(group_parent_id=msg) | 609 error_dict=dict(group_parent_id=msg) |
590 if k.startswith('u_perm_') or k.startswith('g_perm_'): | 657 if k.startswith('u_perm_') or k.startswith('g_perm_'): |
591 member = k[7:] | 658 member = k[7:] |
592 t = {'u': 'user', | 659 t = {'u': 'user', |
593 'g': 'users_group' | 660 'g': 'users_group' |
594 }[k[0]] | 661 }[k[0]] |
595 if member == 'default': | 662 if member == User.DEFAULT_USER: |
596 if str2bool(value.get('repo_private')): | 663 if str2bool(value.get('repo_private')): |
597 # set none for default when updating to | 664 # set none for default when updating to |
598 # private repo protects agains form manipulation | 665 # private repo protects agains form manipulation |
599 v = EMPTY_PERM | 666 v = EMPTY_PERM |
600 perms_update.add((member, v, t)) | 667 perms_update.add((member, v, t)) |
716 | 783 |
717 return _validator | 784 return _validator |
718 | 785 |
719 | 786 |
720 def AttrLoginValidator(): | 787 def AttrLoginValidator(): |
721 class _validator(formencode.validators.FancyValidator): | 788 class _validator(formencode.validators.UnicodeString): |
722 messages = { | 789 messages = { |
723 'invalid_cn': | 790 'invalid_cn': |
724 _(u'The LDAP Login attribute of the CN must be specified - ' | 791 _(u'The LDAP Login attribute of the CN must be specified - ' |
725 'this is the name of the attribute that is equivalent ' | 792 'this is the name of the attribute that is equivalent ' |
726 'to "username"') | 793 'to "username"') |
823 def validate_python(self, value, state): | 890 def validate_python(self, value, state): |
824 if value != os.path.basename(value): | 891 if value != os.path.basename(value): |
825 raise formencode.Invalid(self.message('badPath', state), | 892 raise formencode.Invalid(self.message('badPath', state), |
826 value, state) | 893 value, state) |
827 return _validator | 894 return _validator |
895 | |
896 | |
897 def ValidAuthPlugins(): | |
898 class _validator(formencode.validators.FancyValidator): | |
899 messages = dict( | |
900 import_duplicate=_('Plugins %(loaded)s and %(next_to_load)s both export the same name') | |
901 ) | |
902 | |
903 def _to_python(self, value, state): | |
904 # filter empty values | |
905 return filter(lambda s: s not in [None, ''], value) | |
906 | |
907 def validate_python(self, value, state): | |
908 from rhodecode.lib import auth_modules | |
909 module_list = value | |
910 unique_names = {} | |
911 try: | |
912 for module in module_list: | |
913 plugin = auth_modules.loadplugin(module) | |
914 plugin_name = plugin.name | |
915 if plugin_name in unique_names: | |
916 msg = M(self, 'import_duplicate', state, | |
917 loaded=unique_names[plugin_name], | |
918 next_to_load=plugin_name) | |
919 raise formencode.Invalid(msg, value, state) | |
920 unique_names[plugin_name] = plugin | |
921 except (ImportError, AttributeError, TypeError), e: | |
922 raise formencode.Invalid(str(e), value, state) | |
923 | |
924 return _validator |