##// END OF EJS Templates
validator: fix ASCII password check to verify if it can be *encoded* in ascii...
Mads Kiilerich -
r7959:88e0d0c0 default
parent child Browse files
Show More
@@ -1,804 +1,804 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
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
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
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
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/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 Set of generic validators
15 Set of generic validators
16 """
16 """
17
17
18 import logging
18 import logging
19 import os
19 import os
20 import re
20 import re
21 from collections import defaultdict
21 from collections import defaultdict
22
22
23 import formencode
23 import formencode
24 import ipaddr
24 import ipaddr
25 import sqlalchemy
25 import sqlalchemy
26 from formencode.validators import CIDR, Bool, Email, FancyValidator, Int, IPAddress, NotEmpty, Number, OneOf, Regex, Set, String, StringBoolean, UnicodeString
26 from formencode.validators import CIDR, Bool, Email, FancyValidator, Int, IPAddress, NotEmpty, Number, OneOf, Regex, Set, String, StringBoolean, UnicodeString
27 from sqlalchemy import func
27 from sqlalchemy import func
28 from tg.i18n import ugettext as _
28 from tg.i18n import ugettext as _
29
29
30 from kallithea.config.routing import ADMIN_PREFIX
30 from kallithea.config.routing import ADMIN_PREFIX
31 from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel
31 from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel
32 from kallithea.lib.compat import OrderedSet
32 from kallithea.lib.compat import OrderedSet
33 from kallithea.lib.exceptions import LdapImportError
33 from kallithea.lib.exceptions import LdapImportError
34 from kallithea.lib.utils import is_valid_repo_uri
34 from kallithea.lib.utils import is_valid_repo_uri
35 from kallithea.lib.utils2 import aslist, repo_name_slug, str2bool
35 from kallithea.lib.utils2 import aslist, repo_name_slug, str2bool
36 from kallithea.model.db import RepoGroup, Repository, User, UserGroup
36 from kallithea.model.db import RepoGroup, Repository, User, UserGroup
37
37
38
38
39 # silence warnings and pylint
39 # silence warnings and pylint
40 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
40 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \
41 NotEmpty, IPAddress, CIDR, String, FancyValidator
41 NotEmpty, IPAddress, CIDR, String, FancyValidator
42
42
43 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
44
44
45
45
46 def UniqueListFromString():
46 def UniqueListFromString():
47 class _UniqueListFromString(formencode.FancyValidator):
47 class _UniqueListFromString(formencode.FancyValidator):
48 """
48 """
49 Split value on ',' and make unique while preserving order
49 Split value on ',' and make unique while preserving order
50 """
50 """
51 messages = dict(
51 messages = dict(
52 empty=_('Value cannot be an empty list'),
52 empty=_('Value cannot be an empty list'),
53 missing_value=_('Value cannot be an empty list'),
53 missing_value=_('Value cannot be an empty list'),
54 )
54 )
55
55
56 def _convert_to_python(self, value, state):
56 def _convert_to_python(self, value, state):
57 value = aslist(value, ',')
57 value = aslist(value, ',')
58 seen = set()
58 seen = set()
59 return [c for c in value if not (c in seen or seen.add(c))]
59 return [c for c in value if not (c in seen or seen.add(c))]
60
60
61 def empty_value(self, value):
61 def empty_value(self, value):
62 return []
62 return []
63
63
64 return _UniqueListFromString
64 return _UniqueListFromString
65
65
66
66
67 def ValidUsername(edit=False, old_data=None):
67 def ValidUsername(edit=False, old_data=None):
68 old_data = old_data or {}
68 old_data = old_data or {}
69
69
70 class _validator(formencode.validators.FancyValidator):
70 class _validator(formencode.validators.FancyValidator):
71 messages = {
71 messages = {
72 'username_exists': _('Username "%(username)s" already exists'),
72 'username_exists': _('Username "%(username)s" already exists'),
73 'system_invalid_username':
73 'system_invalid_username':
74 _('Username "%(username)s" cannot be used'),
74 _('Username "%(username)s" cannot be used'),
75 'invalid_username':
75 'invalid_username':
76 _('Username may only contain alphanumeric characters '
76 _('Username may only contain alphanumeric characters '
77 'underscores, periods or dashes and must begin with an '
77 'underscores, periods or dashes and must begin with an '
78 'alphanumeric character or underscore')
78 'alphanumeric character or underscore')
79 }
79 }
80
80
81 def _validate_python(self, value, state):
81 def _validate_python(self, value, state):
82 if value in ['default', 'new_user']:
82 if value in ['default', 'new_user']:
83 msg = self.message('system_invalid_username', state, username=value)
83 msg = self.message('system_invalid_username', state, username=value)
84 raise formencode.Invalid(msg, value, state)
84 raise formencode.Invalid(msg, value, state)
85 # check if user is unique
85 # check if user is unique
86 old_un = None
86 old_un = None
87 if edit:
87 if edit:
88 old_un = User.get(old_data.get('user_id')).username
88 old_un = User.get(old_data.get('user_id')).username
89
89
90 if old_un != value or not edit:
90 if old_un != value or not edit:
91 if User.get_by_username(value, case_insensitive=True):
91 if User.get_by_username(value, case_insensitive=True):
92 msg = self.message('username_exists', state, username=value)
92 msg = self.message('username_exists', state, username=value)
93 raise formencode.Invalid(msg, value, state)
93 raise formencode.Invalid(msg, value, state)
94
94
95 if re.match(r'^[a-zA-Z0-9\_]{1}[a-zA-Z0-9\-\_\.]*$', value) is None:
95 if re.match(r'^[a-zA-Z0-9\_]{1}[a-zA-Z0-9\-\_\.]*$', value) is None:
96 msg = self.message('invalid_username', state)
96 msg = self.message('invalid_username', state)
97 raise formencode.Invalid(msg, value, state)
97 raise formencode.Invalid(msg, value, state)
98 return _validator
98 return _validator
99
99
100
100
101 def ValidRegex(msg=None):
101 def ValidRegex(msg=None):
102 class _validator(formencode.validators.Regex):
102 class _validator(formencode.validators.Regex):
103 messages = dict(invalid=msg or _('The input is not valid'))
103 messages = dict(invalid=msg or _('The input is not valid'))
104 return _validator
104 return _validator
105
105
106
106
107 def ValidRepoUser():
107 def ValidRepoUser():
108 class _validator(formencode.validators.FancyValidator):
108 class _validator(formencode.validators.FancyValidator):
109 messages = {
109 messages = {
110 'invalid_username': _('Username %(username)s is not valid')
110 'invalid_username': _('Username %(username)s is not valid')
111 }
111 }
112
112
113 def _validate_python(self, value, state):
113 def _validate_python(self, value, state):
114 try:
114 try:
115 User.query().filter(User.active == True) \
115 User.query().filter(User.active == True) \
116 .filter(User.username == value).one()
116 .filter(User.username == value).one()
117 except sqlalchemy.exc.InvalidRequestError: # NoResultFound/MultipleResultsFound
117 except sqlalchemy.exc.InvalidRequestError: # NoResultFound/MultipleResultsFound
118 msg = self.message('invalid_username', state, username=value)
118 msg = self.message('invalid_username', state, username=value)
119 raise formencode.Invalid(msg, value, state,
119 raise formencode.Invalid(msg, value, state,
120 error_dict=dict(username=msg)
120 error_dict=dict(username=msg)
121 )
121 )
122
122
123 return _validator
123 return _validator
124
124
125
125
126 def ValidUserGroup(edit=False, old_data=None):
126 def ValidUserGroup(edit=False, old_data=None):
127 old_data = old_data or {}
127 old_data = old_data or {}
128
128
129 class _validator(formencode.validators.FancyValidator):
129 class _validator(formencode.validators.FancyValidator):
130 messages = {
130 messages = {
131 'invalid_group': _('Invalid user group name'),
131 'invalid_group': _('Invalid user group name'),
132 'group_exist': _('User group "%(usergroup)s" already exists'),
132 'group_exist': _('User group "%(usergroup)s" already exists'),
133 'invalid_usergroup_name':
133 'invalid_usergroup_name':
134 _('user group name may only contain alphanumeric '
134 _('user group name may only contain alphanumeric '
135 'characters underscores, periods or dashes and must begin '
135 'characters underscores, periods or dashes and must begin '
136 'with alphanumeric character')
136 'with alphanumeric character')
137 }
137 }
138
138
139 def _validate_python(self, value, state):
139 def _validate_python(self, value, state):
140 if value in ['default']:
140 if value in ['default']:
141 msg = self.message('invalid_group', state)
141 msg = self.message('invalid_group', state)
142 raise formencode.Invalid(msg, value, state,
142 raise formencode.Invalid(msg, value, state,
143 error_dict=dict(users_group_name=msg)
143 error_dict=dict(users_group_name=msg)
144 )
144 )
145 # check if group is unique
145 # check if group is unique
146 old_ugname = None
146 old_ugname = None
147 if edit:
147 if edit:
148 old_id = old_data.get('users_group_id')
148 old_id = old_data.get('users_group_id')
149 old_ugname = UserGroup.get(old_id).users_group_name
149 old_ugname = UserGroup.get(old_id).users_group_name
150
150
151 if old_ugname != value or not edit:
151 if old_ugname != value or not edit:
152 is_existing_group = UserGroup.get_by_group_name(value,
152 is_existing_group = UserGroup.get_by_group_name(value,
153 case_insensitive=True)
153 case_insensitive=True)
154 if is_existing_group:
154 if is_existing_group:
155 msg = self.message('group_exist', state, usergroup=value)
155 msg = self.message('group_exist', state, usergroup=value)
156 raise formencode.Invalid(msg, value, state,
156 raise formencode.Invalid(msg, value, state,
157 error_dict=dict(users_group_name=msg)
157 error_dict=dict(users_group_name=msg)
158 )
158 )
159
159
160 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
160 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
161 msg = self.message('invalid_usergroup_name', state)
161 msg = self.message('invalid_usergroup_name', state)
162 raise formencode.Invalid(msg, value, state,
162 raise formencode.Invalid(msg, value, state,
163 error_dict=dict(users_group_name=msg)
163 error_dict=dict(users_group_name=msg)
164 )
164 )
165
165
166 return _validator
166 return _validator
167
167
168
168
169 def ValidRepoGroup(edit=False, old_data=None):
169 def ValidRepoGroup(edit=False, old_data=None):
170 old_data = old_data or {}
170 old_data = old_data or {}
171
171
172 class _validator(formencode.validators.FancyValidator):
172 class _validator(formencode.validators.FancyValidator):
173 messages = {
173 messages = {
174 'parent_group_id': _('Cannot assign this group as parent'),
174 'parent_group_id': _('Cannot assign this group as parent'),
175 'group_exists': _('Group "%(group_name)s" already exists'),
175 'group_exists': _('Group "%(group_name)s" already exists'),
176 'repo_exists':
176 'repo_exists':
177 _('Repository with name "%(group_name)s" already exists')
177 _('Repository with name "%(group_name)s" already exists')
178 }
178 }
179
179
180 def _validate_python(self, value, state):
180 def _validate_python(self, value, state):
181 # TODO WRITE VALIDATIONS
181 # TODO WRITE VALIDATIONS
182 group_name = value.get('group_name')
182 group_name = value.get('group_name')
183 parent_group_id = value.get('parent_group_id')
183 parent_group_id = value.get('parent_group_id')
184
184
185 # slugify repo group just in case :)
185 # slugify repo group just in case :)
186 slug = repo_name_slug(group_name)
186 slug = repo_name_slug(group_name)
187
187
188 # check for parent of self
188 # check for parent of self
189 parent_of_self = lambda: (
189 parent_of_self = lambda: (
190 old_data['group_id'] == parent_group_id
190 old_data['group_id'] == parent_group_id
191 if parent_group_id else False
191 if parent_group_id else False
192 )
192 )
193 if edit and parent_of_self():
193 if edit and parent_of_self():
194 msg = self.message('parent_group_id', state)
194 msg = self.message('parent_group_id', state)
195 raise formencode.Invalid(msg, value, state,
195 raise formencode.Invalid(msg, value, state,
196 error_dict=dict(parent_group_id=msg)
196 error_dict=dict(parent_group_id=msg)
197 )
197 )
198
198
199 old_gname = None
199 old_gname = None
200 if edit:
200 if edit:
201 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
201 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
202
202
203 if old_gname != group_name or not edit:
203 if old_gname != group_name or not edit:
204
204
205 # check group
205 # check group
206 gr = RepoGroup.query() \
206 gr = RepoGroup.query() \
207 .filter(func.lower(RepoGroup.group_name) == func.lower(slug)) \
207 .filter(func.lower(RepoGroup.group_name) == func.lower(slug)) \
208 .filter(RepoGroup.parent_group_id == parent_group_id) \
208 .filter(RepoGroup.parent_group_id == parent_group_id) \
209 .scalar()
209 .scalar()
210 if gr is not None:
210 if gr is not None:
211 msg = self.message('group_exists', state, group_name=slug)
211 msg = self.message('group_exists', state, group_name=slug)
212 raise formencode.Invalid(msg, value, state,
212 raise formencode.Invalid(msg, value, state,
213 error_dict=dict(group_name=msg)
213 error_dict=dict(group_name=msg)
214 )
214 )
215
215
216 # check for same repo
216 # check for same repo
217 repo = Repository.query() \
217 repo = Repository.query() \
218 .filter(func.lower(Repository.repo_name) == func.lower(slug)) \
218 .filter(func.lower(Repository.repo_name) == func.lower(slug)) \
219 .scalar()
219 .scalar()
220 if repo is not None:
220 if repo is not None:
221 msg = self.message('repo_exists', state, group_name=slug)
221 msg = self.message('repo_exists', state, group_name=slug)
222 raise formencode.Invalid(msg, value, state,
222 raise formencode.Invalid(msg, value, state,
223 error_dict=dict(group_name=msg)
223 error_dict=dict(group_name=msg)
224 )
224 )
225
225
226 return _validator
226 return _validator
227
227
228
228
229 def ValidPassword():
229 def ValidPassword():
230 class _validator(formencode.validators.FancyValidator):
230 class _validator(formencode.validators.FancyValidator):
231 messages = {
231 messages = {
232 'invalid_password':
232 'invalid_password':
233 _('Invalid characters (non-ascii) in password')
233 _('Invalid characters (non-ascii) in password')
234 }
234 }
235
235
236 def _validate_python(self, value, state):
236 def _validate_python(self, value, state):
237 try:
237 try:
238 (value or '').decode('ascii')
238 (value or '').encode('ascii')
239 except UnicodeError:
239 except UnicodeError:
240 msg = self.message('invalid_password', state)
240 msg = self.message('invalid_password', state)
241 raise formencode.Invalid(msg, value, state,)
241 raise formencode.Invalid(msg, value, state,)
242 return _validator
242 return _validator
243
243
244
244
245 def ValidOldPassword(username):
245 def ValidOldPassword(username):
246 class _validator(formencode.validators.FancyValidator):
246 class _validator(formencode.validators.FancyValidator):
247 messages = {
247 messages = {
248 'invalid_password': _('Invalid old password')
248 'invalid_password': _('Invalid old password')
249 }
249 }
250
250
251 def _validate_python(self, value, state):
251 def _validate_python(self, value, state):
252 from kallithea.lib import auth_modules
252 from kallithea.lib import auth_modules
253 if auth_modules.authenticate(username, value, '') is None:
253 if auth_modules.authenticate(username, value, '') is None:
254 msg = self.message('invalid_password', state)
254 msg = self.message('invalid_password', state)
255 raise formencode.Invalid(msg, value, state,
255 raise formencode.Invalid(msg, value, state,
256 error_dict=dict(current_password=msg)
256 error_dict=dict(current_password=msg)
257 )
257 )
258 return _validator
258 return _validator
259
259
260
260
261 def ValidPasswordsMatch(password_field, password_confirmation_field):
261 def ValidPasswordsMatch(password_field, password_confirmation_field):
262 class _validator(formencode.validators.FancyValidator):
262 class _validator(formencode.validators.FancyValidator):
263 messages = {
263 messages = {
264 'password_mismatch': _('Passwords do not match'),
264 'password_mismatch': _('Passwords do not match'),
265 }
265 }
266
266
267 def _validate_python(self, value, state):
267 def _validate_python(self, value, state):
268 if value.get(password_field) != value[password_confirmation_field]:
268 if value.get(password_field) != value[password_confirmation_field]:
269 msg = self.message('password_mismatch', state)
269 msg = self.message('password_mismatch', state)
270 raise formencode.Invalid(msg, value, state,
270 raise formencode.Invalid(msg, value, state,
271 error_dict={password_field: msg, password_confirmation_field: msg}
271 error_dict={password_field: msg, password_confirmation_field: msg}
272 )
272 )
273 return _validator
273 return _validator
274
274
275
275
276 def ValidAuth():
276 def ValidAuth():
277 class _validator(formencode.validators.FancyValidator):
277 class _validator(formencode.validators.FancyValidator):
278 messages = {
278 messages = {
279 'invalid_auth': _(u'Invalid username or password'),
279 'invalid_auth': _(u'Invalid username or password'),
280 }
280 }
281
281
282 def _validate_python(self, value, state):
282 def _validate_python(self, value, state):
283 from kallithea.lib import auth_modules
283 from kallithea.lib import auth_modules
284
284
285 password = value['password']
285 password = value['password']
286 username = value['username']
286 username = value['username']
287
287
288 # authenticate returns unused dict but has called
288 # authenticate returns unused dict but has called
289 # plugin._authenticate which has create_or_update'ed the username user in db
289 # plugin._authenticate which has create_or_update'ed the username user in db
290 if auth_modules.authenticate(username, password) is None:
290 if auth_modules.authenticate(username, password) is None:
291 user = User.get_by_username_or_email(username)
291 user = User.get_by_username_or_email(username)
292 if user and not user.active:
292 if user and not user.active:
293 log.warning('user %s is disabled', username)
293 log.warning('user %s is disabled', username)
294 msg = self.message('invalid_auth', state)
294 msg = self.message('invalid_auth', state)
295 raise formencode.Invalid(msg, value, state,
295 raise formencode.Invalid(msg, value, state,
296 error_dict=dict(username=' ', password=msg)
296 error_dict=dict(username=' ', password=msg)
297 )
297 )
298 else:
298 else:
299 log.warning('user %s failed to authenticate', username)
299 log.warning('user %s failed to authenticate', username)
300 msg = self.message('invalid_auth', state)
300 msg = self.message('invalid_auth', state)
301 raise formencode.Invalid(msg, value, state,
301 raise formencode.Invalid(msg, value, state,
302 error_dict=dict(username=' ', password=msg)
302 error_dict=dict(username=' ', password=msg)
303 )
303 )
304 return _validator
304 return _validator
305
305
306
306
307 def ValidRepoName(edit=False, old_data=None):
307 def ValidRepoName(edit=False, old_data=None):
308 old_data = old_data or {}
308 old_data = old_data or {}
309
309
310 class _validator(formencode.validators.FancyValidator):
310 class _validator(formencode.validators.FancyValidator):
311 messages = {
311 messages = {
312 'invalid_repo_name':
312 'invalid_repo_name':
313 _('Repository name %(repo)s is not allowed'),
313 _('Repository name %(repo)s is not allowed'),
314 'repository_exists':
314 'repository_exists':
315 _('Repository named %(repo)s already exists'),
315 _('Repository named %(repo)s already exists'),
316 'repository_in_group_exists': _('Repository "%(repo)s" already '
316 'repository_in_group_exists': _('Repository "%(repo)s" already '
317 'exists in group "%(group)s"'),
317 'exists in group "%(group)s"'),
318 'same_group_exists': _('Repository group with name "%(repo)s" '
318 'same_group_exists': _('Repository group with name "%(repo)s" '
319 'already exists')
319 'already exists')
320 }
320 }
321
321
322 def _convert_to_python(self, value, state):
322 def _convert_to_python(self, value, state):
323 repo_name = repo_name_slug(value.get('repo_name', ''))
323 repo_name = repo_name_slug(value.get('repo_name', ''))
324 repo_group = value.get('repo_group')
324 repo_group = value.get('repo_group')
325 if repo_group:
325 if repo_group:
326 gr = RepoGroup.get(repo_group)
326 gr = RepoGroup.get(repo_group)
327 group_path = gr.full_path
327 group_path = gr.full_path
328 group_name = gr.group_name
328 group_name = gr.group_name
329 # value needs to be aware of group name in order to check
329 # value needs to be aware of group name in order to check
330 # db key This is an actual just the name to store in the
330 # db key This is an actual just the name to store in the
331 # database
331 # database
332 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
332 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
333 else:
333 else:
334 group_name = group_path = ''
334 group_name = group_path = ''
335 repo_name_full = repo_name
335 repo_name_full = repo_name
336
336
337 value['repo_name'] = repo_name
337 value['repo_name'] = repo_name
338 value['repo_name_full'] = repo_name_full
338 value['repo_name_full'] = repo_name_full
339 value['group_path'] = group_path
339 value['group_path'] = group_path
340 value['group_name'] = group_name
340 value['group_name'] = group_name
341 return value
341 return value
342
342
343 def _validate_python(self, value, state):
343 def _validate_python(self, value, state):
344 repo_name = value.get('repo_name')
344 repo_name = value.get('repo_name')
345 repo_name_full = value.get('repo_name_full')
345 repo_name_full = value.get('repo_name_full')
346 group_path = value.get('group_path')
346 group_path = value.get('group_path')
347 group_name = value.get('group_name')
347 group_name = value.get('group_name')
348
348
349 if repo_name in [ADMIN_PREFIX, '']:
349 if repo_name in [ADMIN_PREFIX, '']:
350 msg = self.message('invalid_repo_name', state, repo=repo_name)
350 msg = self.message('invalid_repo_name', state, repo=repo_name)
351 raise formencode.Invalid(msg, value, state,
351 raise formencode.Invalid(msg, value, state,
352 error_dict=dict(repo_name=msg)
352 error_dict=dict(repo_name=msg)
353 )
353 )
354
354
355 rename = old_data.get('repo_name') != repo_name_full
355 rename = old_data.get('repo_name') != repo_name_full
356 create = not edit
356 create = not edit
357 if rename or create:
357 if rename or create:
358 repo = Repository.get_by_repo_name(repo_name_full, case_insensitive=True)
358 repo = Repository.get_by_repo_name(repo_name_full, case_insensitive=True)
359 repo_group = RepoGroup.get_by_group_name(repo_name_full, case_insensitive=True)
359 repo_group = RepoGroup.get_by_group_name(repo_name_full, case_insensitive=True)
360 if group_path != '':
360 if group_path != '':
361 if repo is not None:
361 if repo is not None:
362 msg = self.message('repository_in_group_exists', state,
362 msg = self.message('repository_in_group_exists', state,
363 repo=repo.repo_name, group=group_name)
363 repo=repo.repo_name, group=group_name)
364 raise formencode.Invalid(msg, value, state,
364 raise formencode.Invalid(msg, value, state,
365 error_dict=dict(repo_name=msg)
365 error_dict=dict(repo_name=msg)
366 )
366 )
367 elif repo_group is not None:
367 elif repo_group is not None:
368 msg = self.message('same_group_exists', state,
368 msg = self.message('same_group_exists', state,
369 repo=repo_name)
369 repo=repo_name)
370 raise formencode.Invalid(msg, value, state,
370 raise formencode.Invalid(msg, value, state,
371 error_dict=dict(repo_name=msg)
371 error_dict=dict(repo_name=msg)
372 )
372 )
373 elif repo is not None:
373 elif repo is not None:
374 msg = self.message('repository_exists', state,
374 msg = self.message('repository_exists', state,
375 repo=repo.repo_name)
375 repo=repo.repo_name)
376 raise formencode.Invalid(msg, value, state,
376 raise formencode.Invalid(msg, value, state,
377 error_dict=dict(repo_name=msg)
377 error_dict=dict(repo_name=msg)
378 )
378 )
379 return value
379 return value
380 return _validator
380 return _validator
381
381
382
382
383 def ValidForkName(*args, **kwargs):
383 def ValidForkName(*args, **kwargs):
384 return ValidRepoName(*args, **kwargs)
384 return ValidRepoName(*args, **kwargs)
385
385
386
386
387 def SlugifyName():
387 def SlugifyName():
388 class _validator(formencode.validators.FancyValidator):
388 class _validator(formencode.validators.FancyValidator):
389
389
390 def _convert_to_python(self, value, state):
390 def _convert_to_python(self, value, state):
391 return repo_name_slug(value)
391 return repo_name_slug(value)
392
392
393 def _validate_python(self, value, state):
393 def _validate_python(self, value, state):
394 pass
394 pass
395
395
396 return _validator
396 return _validator
397
397
398
398
399 def ValidCloneUri():
399 def ValidCloneUri():
400 from kallithea.lib.utils import make_ui
400 from kallithea.lib.utils import make_ui
401
401
402 class _validator(formencode.validators.FancyValidator):
402 class _validator(formencode.validators.FancyValidator):
403 messages = {
403 messages = {
404 'clone_uri': _('Invalid repository URL'),
404 'clone_uri': _('Invalid repository URL'),
405 'invalid_clone_uri': _('Invalid repository URL. It must be a '
405 'invalid_clone_uri': _('Invalid repository URL. It must be a '
406 'valid http, https, ssh, svn+http or svn+https URL'),
406 'valid http, https, ssh, svn+http or svn+https URL'),
407 }
407 }
408
408
409 def _validate_python(self, value, state):
409 def _validate_python(self, value, state):
410 repo_type = value.get('repo_type')
410 repo_type = value.get('repo_type')
411 url = value.get('clone_uri')
411 url = value.get('clone_uri')
412
412
413 if url and url != value.get('clone_uri_hidden'):
413 if url and url != value.get('clone_uri_hidden'):
414 try:
414 try:
415 is_valid_repo_uri(repo_type, url, make_ui())
415 is_valid_repo_uri(repo_type, url, make_ui())
416 except Exception:
416 except Exception:
417 log.exception('URL validation failed')
417 log.exception('URL validation failed')
418 msg = self.message('clone_uri', state)
418 msg = self.message('clone_uri', state)
419 raise formencode.Invalid(msg, value, state,
419 raise formencode.Invalid(msg, value, state,
420 error_dict=dict(clone_uri=msg)
420 error_dict=dict(clone_uri=msg)
421 )
421 )
422 return _validator
422 return _validator
423
423
424
424
425 def ValidForkType(old_data=None):
425 def ValidForkType(old_data=None):
426 old_data = old_data or {}
426 old_data = old_data or {}
427
427
428 class _validator(formencode.validators.FancyValidator):
428 class _validator(formencode.validators.FancyValidator):
429 messages = {
429 messages = {
430 'invalid_fork_type': _('Fork has to be the same type as parent')
430 'invalid_fork_type': _('Fork has to be the same type as parent')
431 }
431 }
432
432
433 def _validate_python(self, value, state):
433 def _validate_python(self, value, state):
434 if old_data['repo_type'] != value:
434 if old_data['repo_type'] != value:
435 msg = self.message('invalid_fork_type', state)
435 msg = self.message('invalid_fork_type', state)
436 raise formencode.Invalid(msg, value, state,
436 raise formencode.Invalid(msg, value, state,
437 error_dict=dict(repo_type=msg)
437 error_dict=dict(repo_type=msg)
438 )
438 )
439 return _validator
439 return _validator
440
440
441
441
442 def CanWriteGroup(old_data=None):
442 def CanWriteGroup(old_data=None):
443 class _validator(formencode.validators.FancyValidator):
443 class _validator(formencode.validators.FancyValidator):
444 messages = {
444 messages = {
445 'permission_denied': _("You don't have permissions "
445 'permission_denied': _("You don't have permissions "
446 "to create repository in this group"),
446 "to create repository in this group"),
447 'permission_denied_root': _("no permission to create repository "
447 'permission_denied_root': _("no permission to create repository "
448 "in root location")
448 "in root location")
449 }
449 }
450
450
451 def _convert_to_python(self, value, state):
451 def _convert_to_python(self, value, state):
452 # root location
452 # root location
453 if value == -1:
453 if value == -1:
454 return None
454 return None
455 return value
455 return value
456
456
457 def _validate_python(self, value, state):
457 def _validate_python(self, value, state):
458 gr = RepoGroup.get(value)
458 gr = RepoGroup.get(value)
459 gr_name = gr.group_name if gr is not None else None # None means ROOT location
459 gr_name = gr.group_name if gr is not None else None # None means ROOT location
460
460
461 # create repositories with write permission on group is set to true
461 # create repositories with write permission on group is set to true
462 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
462 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
463 group_admin = HasRepoGroupPermissionLevel('admin')(gr_name,
463 group_admin = HasRepoGroupPermissionLevel('admin')(gr_name,
464 'can write into group validator')
464 'can write into group validator')
465 group_write = HasRepoGroupPermissionLevel('write')(gr_name,
465 group_write = HasRepoGroupPermissionLevel('write')(gr_name,
466 'can write into group validator')
466 'can write into group validator')
467 forbidden = not (group_admin or (group_write and create_on_write))
467 forbidden = not (group_admin or (group_write and create_on_write))
468 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository')
468 can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository')
469 gid = (old_data['repo_group'].get('group_id')
469 gid = (old_data['repo_group'].get('group_id')
470 if (old_data and 'repo_group' in old_data) else None)
470 if (old_data and 'repo_group' in old_data) else None)
471 value_changed = gid != value
471 value_changed = gid != value
472 new = not old_data
472 new = not old_data
473 # do check if we changed the value, there's a case that someone got
473 # do check if we changed the value, there's a case that someone got
474 # revoked write permissions to a repository, he still created, we
474 # revoked write permissions to a repository, he still created, we
475 # don't need to check permission if he didn't change the value of
475 # don't need to check permission if he didn't change the value of
476 # groups in form box
476 # groups in form box
477 if value_changed or new:
477 if value_changed or new:
478 # parent group need to be existing
478 # parent group need to be existing
479 if gr and forbidden:
479 if gr and forbidden:
480 msg = self.message('permission_denied', state)
480 msg = self.message('permission_denied', state)
481 raise formencode.Invalid(msg, value, state,
481 raise formencode.Invalid(msg, value, state,
482 error_dict=dict(repo_type=msg)
482 error_dict=dict(repo_type=msg)
483 )
483 )
484 ## check if we can write to root location !
484 ## check if we can write to root location !
485 elif gr is None and not can_create_repos():
485 elif gr is None and not can_create_repos():
486 msg = self.message('permission_denied_root', state)
486 msg = self.message('permission_denied_root', state)
487 raise formencode.Invalid(msg, value, state,
487 raise formencode.Invalid(msg, value, state,
488 error_dict=dict(repo_type=msg)
488 error_dict=dict(repo_type=msg)
489 )
489 )
490
490
491 return _validator
491 return _validator
492
492
493
493
494 def CanCreateGroup(can_create_in_root=False):
494 def CanCreateGroup(can_create_in_root=False):
495 class _validator(formencode.validators.FancyValidator):
495 class _validator(formencode.validators.FancyValidator):
496 messages = {
496 messages = {
497 'permission_denied': _("You don't have permissions "
497 'permission_denied': _("You don't have permissions "
498 "to create a group in this location")
498 "to create a group in this location")
499 }
499 }
500
500
501 def to_python(self, value, state):
501 def to_python(self, value, state):
502 # root location
502 # root location
503 if value == -1:
503 if value == -1:
504 return None
504 return None
505 return value
505 return value
506
506
507 def _validate_python(self, value, state):
507 def _validate_python(self, value, state):
508 gr = RepoGroup.get(value)
508 gr = RepoGroup.get(value)
509 gr_name = gr.group_name if gr is not None else None # None means ROOT location
509 gr_name = gr.group_name if gr is not None else None # None means ROOT location
510
510
511 if can_create_in_root and gr is None:
511 if can_create_in_root and gr is None:
512 # we can create in root, we're fine no validations required
512 # we can create in root, we're fine no validations required
513 return
513 return
514
514
515 forbidden_in_root = gr is None and not can_create_in_root
515 forbidden_in_root = gr is None and not can_create_in_root
516 forbidden = not HasRepoGroupPermissionLevel('admin')(gr_name, 'can create group validator')
516 forbidden = not HasRepoGroupPermissionLevel('admin')(gr_name, 'can create group validator')
517 if forbidden_in_root or forbidden:
517 if forbidden_in_root or forbidden:
518 msg = self.message('permission_denied', state)
518 msg = self.message('permission_denied', state)
519 raise formencode.Invalid(msg, value, state,
519 raise formencode.Invalid(msg, value, state,
520 error_dict=dict(parent_group_id=msg)
520 error_dict=dict(parent_group_id=msg)
521 )
521 )
522
522
523 return _validator
523 return _validator
524
524
525
525
526 def ValidPerms(type_='repo'):
526 def ValidPerms(type_='repo'):
527 if type_ == 'repo_group':
527 if type_ == 'repo_group':
528 EMPTY_PERM = 'group.none'
528 EMPTY_PERM = 'group.none'
529 elif type_ == 'repo':
529 elif type_ == 'repo':
530 EMPTY_PERM = 'repository.none'
530 EMPTY_PERM = 'repository.none'
531 elif type_ == 'user_group':
531 elif type_ == 'user_group':
532 EMPTY_PERM = 'usergroup.none'
532 EMPTY_PERM = 'usergroup.none'
533
533
534 class _validator(formencode.validators.FancyValidator):
534 class _validator(formencode.validators.FancyValidator):
535 messages = {
535 messages = {
536 'perm_new_member_name':
536 'perm_new_member_name':
537 _('This username or user group name is not valid')
537 _('This username or user group name is not valid')
538 }
538 }
539
539
540 def to_python(self, value, state):
540 def to_python(self, value, state):
541 perms_update = OrderedSet()
541 perms_update = OrderedSet()
542 perms_new = OrderedSet()
542 perms_new = OrderedSet()
543 # build a list of permission to update and new permission to create
543 # build a list of permission to update and new permission to create
544
544
545 # CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
545 # CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using
546 new_perms_group = defaultdict(dict)
546 new_perms_group = defaultdict(dict)
547 for k, v in value.copy().iteritems():
547 for k, v in value.copy().iteritems():
548 if k.startswith('perm_new_member'):
548 if k.startswith('perm_new_member'):
549 del value[k]
549 del value[k]
550 _type, part = k.split('perm_new_member_')
550 _type, part = k.split('perm_new_member_')
551 args = part.split('_')
551 args = part.split('_')
552 if len(args) == 1:
552 if len(args) == 1:
553 new_perms_group[args[0]]['perm'] = v
553 new_perms_group[args[0]]['perm'] = v
554 elif len(args) == 2:
554 elif len(args) == 2:
555 _key, pos = args
555 _key, pos = args
556 new_perms_group[pos][_key] = v
556 new_perms_group[pos][_key] = v
557
557
558 # fill new permissions in order of how they were added
558 # fill new permissions in order of how they were added
559 for k in sorted(new_perms_group, key=lambda k: int(k)):
559 for k in sorted(new_perms_group, key=lambda k: int(k)):
560 perm_dict = new_perms_group[k]
560 perm_dict = new_perms_group[k]
561 new_member = perm_dict.get('name')
561 new_member = perm_dict.get('name')
562 new_perm = perm_dict.get('perm')
562 new_perm = perm_dict.get('perm')
563 new_type = perm_dict.get('type')
563 new_type = perm_dict.get('type')
564 if new_member and new_perm and new_type:
564 if new_member and new_perm and new_type:
565 perms_new.add((new_member, new_perm, new_type))
565 perms_new.add((new_member, new_perm, new_type))
566
566
567 for k, v in value.iteritems():
567 for k, v in value.iteritems():
568 if k.startswith('u_perm_') or k.startswith('g_perm_'):
568 if k.startswith('u_perm_') or k.startswith('g_perm_'):
569 member = k[7:]
569 member = k[7:]
570 t = {'u': 'user',
570 t = {'u': 'user',
571 'g': 'users_group'
571 'g': 'users_group'
572 }[k[0]]
572 }[k[0]]
573 if member == User.DEFAULT_USER:
573 if member == User.DEFAULT_USER:
574 if str2bool(value.get('repo_private')):
574 if str2bool(value.get('repo_private')):
575 # set none for default when updating to
575 # set none for default when updating to
576 # private repo protects against form manipulation
576 # private repo protects against form manipulation
577 v = EMPTY_PERM
577 v = EMPTY_PERM
578 perms_update.add((member, v, t))
578 perms_update.add((member, v, t))
579
579
580 value['perms_updates'] = list(perms_update)
580 value['perms_updates'] = list(perms_update)
581 value['perms_new'] = list(perms_new)
581 value['perms_new'] = list(perms_new)
582
582
583 # update permissions
583 # update permissions
584 for k, v, t in perms_new:
584 for k, v, t in perms_new:
585 try:
585 try:
586 if t == 'user':
586 if t == 'user':
587 self.user_db = User.query() \
587 self.user_db = User.query() \
588 .filter(User.active == True) \
588 .filter(User.active == True) \
589 .filter(User.username == k).one()
589 .filter(User.username == k).one()
590 if t == 'users_group':
590 if t == 'users_group':
591 self.user_db = UserGroup.query() \
591 self.user_db = UserGroup.query() \
592 .filter(UserGroup.users_group_active == True) \
592 .filter(UserGroup.users_group_active == True) \
593 .filter(UserGroup.users_group_name == k).one()
593 .filter(UserGroup.users_group_name == k).one()
594
594
595 except Exception:
595 except Exception:
596 log.exception('Updated permission failed')
596 log.exception('Updated permission failed')
597 msg = self.message('perm_new_member_type', state)
597 msg = self.message('perm_new_member_type', state)
598 raise formencode.Invalid(msg, value, state,
598 raise formencode.Invalid(msg, value, state,
599 error_dict=dict(perm_new_member_name=msg)
599 error_dict=dict(perm_new_member_name=msg)
600 )
600 )
601 return value
601 return value
602 return _validator
602 return _validator
603
603
604
604
605 def ValidSettings():
605 def ValidSettings():
606 class _validator(formencode.validators.FancyValidator):
606 class _validator(formencode.validators.FancyValidator):
607 def _convert_to_python(self, value, state):
607 def _convert_to_python(self, value, state):
608 # settings form for users that are not admin
608 # settings form for users that are not admin
609 # can't edit certain parameters, it's extra backup if they mangle
609 # can't edit certain parameters, it's extra backup if they mangle
610 # with forms
610 # with forms
611
611
612 forbidden_params = [
612 forbidden_params = [
613 'user', 'repo_type',
613 'user', 'repo_type',
614 'repo_enable_downloads', 'repo_enable_statistics'
614 'repo_enable_downloads', 'repo_enable_statistics'
615 ]
615 ]
616
616
617 for param in forbidden_params:
617 for param in forbidden_params:
618 if param in value:
618 if param in value:
619 del value[param]
619 del value[param]
620 return value
620 return value
621
621
622 def _validate_python(self, value, state):
622 def _validate_python(self, value, state):
623 pass
623 pass
624 return _validator
624 return _validator
625
625
626
626
627 def ValidPath():
627 def ValidPath():
628 class _validator(formencode.validators.FancyValidator):
628 class _validator(formencode.validators.FancyValidator):
629 messages = {
629 messages = {
630 'invalid_path': _('This is not a valid path')
630 'invalid_path': _('This is not a valid path')
631 }
631 }
632
632
633 def _validate_python(self, value, state):
633 def _validate_python(self, value, state):
634 if not os.path.isdir(value):
634 if not os.path.isdir(value):
635 msg = self.message('invalid_path', state)
635 msg = self.message('invalid_path', state)
636 raise formencode.Invalid(msg, value, state,
636 raise formencode.Invalid(msg, value, state,
637 error_dict=dict(paths_root_path=msg)
637 error_dict=dict(paths_root_path=msg)
638 )
638 )
639 return _validator
639 return _validator
640
640
641
641
642 def UniqSystemEmail(old_data=None):
642 def UniqSystemEmail(old_data=None):
643 old_data = old_data or {}
643 old_data = old_data or {}
644
644
645 class _validator(formencode.validators.FancyValidator):
645 class _validator(formencode.validators.FancyValidator):
646 messages = {
646 messages = {
647 'email_taken': _('This email address is already in use')
647 'email_taken': _('This email address is already in use')
648 }
648 }
649
649
650 def _convert_to_python(self, value, state):
650 def _convert_to_python(self, value, state):
651 return value.lower()
651 return value.lower()
652
652
653 def _validate_python(self, value, state):
653 def _validate_python(self, value, state):
654 if (old_data.get('email') or '').lower() != value:
654 if (old_data.get('email') or '').lower() != value:
655 user = User.get_by_email(value)
655 user = User.get_by_email(value)
656 if user is not None:
656 if user is not None:
657 msg = self.message('email_taken', state)
657 msg = self.message('email_taken', state)
658 raise formencode.Invalid(msg, value, state,
658 raise formencode.Invalid(msg, value, state,
659 error_dict=dict(email=msg)
659 error_dict=dict(email=msg)
660 )
660 )
661 return _validator
661 return _validator
662
662
663
663
664 def ValidSystemEmail():
664 def ValidSystemEmail():
665 class _validator(formencode.validators.FancyValidator):
665 class _validator(formencode.validators.FancyValidator):
666 messages = {
666 messages = {
667 'non_existing_email': _('Email address "%(email)s" not found')
667 'non_existing_email': _('Email address "%(email)s" not found')
668 }
668 }
669
669
670 def _convert_to_python(self, value, state):
670 def _convert_to_python(self, value, state):
671 return value.lower()
671 return value.lower()
672
672
673 def _validate_python(self, value, state):
673 def _validate_python(self, value, state):
674 user = User.get_by_email(value)
674 user = User.get_by_email(value)
675 if user is None:
675 if user is None:
676 msg = self.message('non_existing_email', state, email=value)
676 msg = self.message('non_existing_email', state, email=value)
677 raise formencode.Invalid(msg, value, state,
677 raise formencode.Invalid(msg, value, state,
678 error_dict=dict(email=msg)
678 error_dict=dict(email=msg)
679 )
679 )
680
680
681 return _validator
681 return _validator
682
682
683
683
684 def LdapLibValidator():
684 def LdapLibValidator():
685 class _validator(formencode.validators.FancyValidator):
685 class _validator(formencode.validators.FancyValidator):
686 messages = {
686 messages = {
687
687
688 }
688 }
689
689
690 def _validate_python(self, value, state):
690 def _validate_python(self, value, state):
691 try:
691 try:
692 import ldap
692 import ldap
693 ldap # pyflakes silence !
693 ldap # pyflakes silence !
694 except ImportError:
694 except ImportError:
695 raise LdapImportError()
695 raise LdapImportError()
696
696
697 return _validator
697 return _validator
698
698
699
699
700 def AttrLoginValidator():
700 def AttrLoginValidator():
701 class _validator(formencode.validators.UnicodeString):
701 class _validator(formencode.validators.UnicodeString):
702 messages = {
702 messages = {
703 'invalid_cn':
703 'invalid_cn':
704 _('The LDAP Login attribute of the CN must be specified - '
704 _('The LDAP Login attribute of the CN must be specified - '
705 'this is the name of the attribute that is equivalent '
705 'this is the name of the attribute that is equivalent '
706 'to "username"')
706 'to "username"')
707 }
707 }
708 messages['empty'] = messages['invalid_cn']
708 messages['empty'] = messages['invalid_cn']
709
709
710 return _validator
710 return _validator
711
711
712
712
713 def ValidIp():
713 def ValidIp():
714 class _validator(CIDR):
714 class _validator(CIDR):
715 messages = dict(
715 messages = dict(
716 badFormat=_('Please enter a valid IPv4 or IPv6 address'),
716 badFormat=_('Please enter a valid IPv4 or IPv6 address'),
717 illegalBits=_('The network size (bits) must be within the range'
717 illegalBits=_('The network size (bits) must be within the range'
718 ' of 0-32 (not %(bits)r)')
718 ' of 0-32 (not %(bits)r)')
719 )
719 )
720
720
721 def to_python(self, value, state):
721 def to_python(self, value, state):
722 v = super(_validator, self).to_python(value, state)
722 v = super(_validator, self).to_python(value, state)
723 v = v.strip()
723 v = v.strip()
724 net = ipaddr.IPNetwork(address=v)
724 net = ipaddr.IPNetwork(address=v)
725 if isinstance(net, ipaddr.IPv4Network):
725 if isinstance(net, ipaddr.IPv4Network):
726 # if IPv4 doesn't end with a mask, add /32
726 # if IPv4 doesn't end with a mask, add /32
727 if '/' not in value:
727 if '/' not in value:
728 v += '/32'
728 v += '/32'
729 if isinstance(net, ipaddr.IPv6Network):
729 if isinstance(net, ipaddr.IPv6Network):
730 # if IPv6 doesn't end with a mask, add /128
730 # if IPv6 doesn't end with a mask, add /128
731 if '/' not in value:
731 if '/' not in value:
732 v += '/128'
732 v += '/128'
733 return v
733 return v
734
734
735 def _validate_python(self, value, state):
735 def _validate_python(self, value, state):
736 try:
736 try:
737 addr = value.strip()
737 addr = value.strip()
738 # this raises an ValueError if address is not IPv4 or IPv6
738 # this raises an ValueError if address is not IPv4 or IPv6
739 ipaddr.IPNetwork(address=addr)
739 ipaddr.IPNetwork(address=addr)
740 except ValueError:
740 except ValueError:
741 raise formencode.Invalid(self.message('badFormat', state),
741 raise formencode.Invalid(self.message('badFormat', state),
742 value, state)
742 value, state)
743
743
744 return _validator
744 return _validator
745
745
746
746
747 def FieldKey():
747 def FieldKey():
748 class _validator(formencode.validators.FancyValidator):
748 class _validator(formencode.validators.FancyValidator):
749 messages = dict(
749 messages = dict(
750 badFormat=_('Key name can only consist of letters, '
750 badFormat=_('Key name can only consist of letters, '
751 'underscore, dash or numbers')
751 'underscore, dash or numbers')
752 )
752 )
753
753
754 def _validate_python(self, value, state):
754 def _validate_python(self, value, state):
755 if not re.match('[a-zA-Z0-9_-]+$', value):
755 if not re.match('[a-zA-Z0-9_-]+$', value):
756 raise formencode.Invalid(self.message('badFormat', state),
756 raise formencode.Invalid(self.message('badFormat', state),
757 value, state)
757 value, state)
758 return _validator
758 return _validator
759
759
760
760
761 def BasePath():
761 def BasePath():
762 class _validator(formencode.validators.FancyValidator):
762 class _validator(formencode.validators.FancyValidator):
763 messages = dict(
763 messages = dict(
764 badPath=_('Filename cannot be inside a directory')
764 badPath=_('Filename cannot be inside a directory')
765 )
765 )
766
766
767 def _convert_to_python(self, value, state):
767 def _convert_to_python(self, value, state):
768 return value
768 return value
769
769
770 def _validate_python(self, value, state):
770 def _validate_python(self, value, state):
771 if value != os.path.basename(value):
771 if value != os.path.basename(value):
772 raise formencode.Invalid(self.message('badPath', state),
772 raise formencode.Invalid(self.message('badPath', state),
773 value, state)
773 value, state)
774 return _validator
774 return _validator
775
775
776
776
777 def ValidAuthPlugins():
777 def ValidAuthPlugins():
778 class _validator(formencode.validators.FancyValidator):
778 class _validator(formencode.validators.FancyValidator):
779 messages = dict(
779 messages = dict(
780 import_duplicate=_('Plugins %(loaded)s and %(next_to_load)s both export the same name')
780 import_duplicate=_('Plugins %(loaded)s and %(next_to_load)s both export the same name')
781 )
781 )
782
782
783 def _convert_to_python(self, value, state):
783 def _convert_to_python(self, value, state):
784 # filter empty values
784 # filter empty values
785 return [s for s in value if s not in [None, '']]
785 return [s for s in value if s not in [None, '']]
786
786
787 def _validate_python(self, value, state):
787 def _validate_python(self, value, state):
788 from kallithea.lib import auth_modules
788 from kallithea.lib import auth_modules
789 module_list = value
789 module_list = value
790 unique_names = {}
790 unique_names = {}
791 try:
791 try:
792 for module in module_list:
792 for module in module_list:
793 plugin = auth_modules.loadplugin(module)
793 plugin = auth_modules.loadplugin(module)
794 plugin_name = plugin.name
794 plugin_name = plugin.name
795 if plugin_name in unique_names:
795 if plugin_name in unique_names:
796 msg = self.message('import_duplicate', state,
796 msg = self.message('import_duplicate', state,
797 loaded=unique_names[plugin_name],
797 loaded=unique_names[plugin_name],
798 next_to_load=plugin_name)
798 next_to_load=plugin_name)
799 raise formencode.Invalid(msg, value, state)
799 raise formencode.Invalid(msg, value, state)
800 unique_names[plugin_name] = plugin
800 unique_names[plugin_name] = plugin
801 except (ImportError, AttributeError, TypeError) as e:
801 except (ImportError, AttributeError, TypeError) as e:
802 raise formencode.Invalid(str(e), value, state)
802 raise formencode.Invalid(str(e), value, state)
803
803
804 return _validator
804 return _validator
General Comments 0
You need to be logged in to leave comments. Login now