##// END OF EJS Templates
updated with a latest changes.
ilin.s -
r5536:2c8dbdc5 merge default
parent child Browse files
Show More
@@ -0,0 +1,17 b''
1
2 def apply_license(*args, **kwargs):
3 pass
4
5 try:
6 from rc_license.models import apply_license
7 except ImportError:
8 pass
9
10
11 def apply_license_from_file(*args, **kwargs):
12 pass
13
14 try:
15 from rc_license.models import apply_license_from_file
16 except ImportError:
17 pass
@@ -33,7 +33,7 b' channelstream==0.7.1'
33 33 gevent==24.2.1
34 34 greenlet==3.0.3
35 35 zope.event==5.0.0
36 zope.interface==6.4.post2
36 zope.interface==7.0.3
37 37 itsdangerous==1.1.0
38 38 marshmallow==2.18.0
39 39 pyramid==2.0.2
@@ -46,7 +46,7 b' channelstream==0.7.1'
46 46 venusian==3.0.0
47 47 webob==1.8.7
48 48 zope.deprecation==5.0.0
49 zope.interface==6.4.post2
49 zope.interface==7.0.3
50 50 pyramid-jinja2==2.10
51 51 jinja2==3.1.2
52 52 markupsafe==2.1.2
@@ -61,7 +61,7 b' channelstream==0.7.1'
61 61 venusian==3.0.0
62 62 webob==1.8.7
63 63 zope.deprecation==5.0.0
64 zope.interface==6.4.post2
64 zope.interface==7.0.3
65 65 zope.deprecation==5.0.0
66 66 python-dateutil==2.8.2
67 67 six==1.16.0
@@ -87,13 +87,13 b' dogpile.cache==1.3.3'
87 87 pbr==5.11.1
88 88 formencode==2.1.0
89 89 six==1.16.0
90 fsspec==2024.6.0
90 fsspec==2024.9.0
91 91 gunicorn==23.0.0
92 92 packaging==24.1
93 93 gevent==24.2.1
94 94 greenlet==3.0.3
95 95 zope.event==5.0.0
96 zope.interface==6.4.post2
96 zope.interface==7.0.3
97 97 ipython==8.26.0
98 98 decorator==5.1.1
99 99 jedi==0.19.1
@@ -167,7 +167,7 b' nbconvert==7.7.3'
167 167 tinycss2==1.2.1
168 168 webencodings==0.5.1
169 169 traitlets==5.14.3
170 orjson==3.10.6
170 orjson==3.10.7
171 171 paste==3.10.1
172 172 premailer==3.10.0
173 173 cachetools==5.3.3
@@ -201,13 +201,13 b' pyramid-mailer==0.15.1'
201 201 venusian==3.0.0
202 202 webob==1.8.7
203 203 zope.deprecation==5.0.0
204 zope.interface==6.4.post2
204 zope.interface==7.0.3
205 205 repoze.sendmail==4.4.1
206 transaction==3.1.0
207 zope.interface==6.4.post2
208 zope.interface==6.4.post2
209 transaction==3.1.0
210 zope.interface==6.4.post2
206 transaction==5.0.0
207 zope.interface==7.0.3
208 zope.interface==7.0.3
209 transaction==5.0.0
210 zope.interface==7.0.3
211 211 pyramid-mako==1.1.0
212 212 mako==1.2.4
213 213 markupsafe==2.1.2
@@ -221,7 +221,7 b' pyramid-mako==1.1.0'
221 221 venusian==3.0.0
222 222 webob==1.8.7
223 223 zope.deprecation==5.0.0
224 zope.interface==6.4.post2
224 zope.interface==7.0.3
225 225 python-ldap==3.4.3
226 226 pyasn1==0.4.8
227 227 pyasn1-modules==0.2.8
@@ -236,13 +236,13 b' python3-saml==1.16.0'
236 236 xmlsec==1.3.14
237 237 lxml==5.3.0
238 238 pyyaml==6.0.1
239 redis==5.0.4
239 redis==5.1.0
240 240 async-timeout==4.0.3
241 241 regex==2022.10.31
242 242 routes==2.5.1
243 243 repoze.lru==0.7
244 244 six==1.16.0
245 s3fs==2024.6.0
245 s3fs==2024.9.0
246 246 aiobotocore==2.13.0
247 247 aiohttp==3.9.5
248 248 aiosignal==1.3.1
@@ -269,7 +269,7 b' s3fs==2024.6.0'
269 269 yarl==1.9.4
270 270 idna==3.4
271 271 multidict==6.0.5
272 fsspec==2024.6.0
272 fsspec==2024.9.0
273 273 simplejson==3.19.2
274 274 sshpubkeys==3.3.1
275 275 cryptography==40.0.2
@@ -67,7 +67,7 b' def admin_routes(config):'
67 67
68 68 config.add_route(
69 69 name='admin_security_modify_allowed_vcs_client_versions',
70 pattern='/security/modify/allowed_vcs_client_versions')
70 pattern=ADMIN_PREFIX + '/security/modify/allowed_vcs_client_versions')
71 71 config.add_view(
72 72 AdminSecurityView,
73 73 attr='vcs_whitelisted_client_versions_edit',
@@ -17,13 +17,8 b''
17 17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 18
19 19 import logging
20 import formencode
21 20
22 from rhodecode import BACKENDS
23 21 from rhodecode.apps._base import BaseAppView
24 from rhodecode.model.meta import Session
25 from rhodecode.model.settings import SettingsModel
26 from rhodecode.model.forms import WhitelistedVcsClientsForm
27 22 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
28 23
29 24 log = logging.getLogger(__name__)
@@ -42,31 +37,10 b' class AdminSecurityView(BaseAppView):'
42 37 c.active = 'security'
43 38 return self._get_template_context(c)
44 39
40
45 41 @LoginRequired()
46 42 @HasPermissionAllDecorator('hg.admin')
47 def vcs_whitelisted_client_versions_edit(self):
48 _ = self.request.translate
43 def admin_security_modify_allowed_vcs_client_versions(self):
49 44 c = self.load_default_context()
50 render_ctx = {}
51 settings = SettingsModel()
52 form = WhitelistedVcsClientsForm(_, )()
53 if self.request.method == 'POST':
54 try:
55 result = form.to_python(self.request.POST)
56 for k, v in result.items():
57 if v:
58 setting = settings.create_or_update_setting(name=f'{k}_allowed_clients', val=v)
59 Session().add(setting)
60 Session().commit()
61
62 except formencode.Invalid as errors:
63 render_ctx.update({
64 'errors': errors.error_dict
65 })
66 for key in BACKENDS.keys():
67 verbose_name = f"initial_{key}"
68 if existing := settings.get_setting_by_name(name=f'{key}_allowed_clients'):
69 render_ctx[verbose_name] = existing.app_settings_value
70 else:
71 render_ctx[verbose_name] = '*'
72 return self._get_template_context(c, **render_ctx)
45 c.active = 'security'
46 return self._get_template_context(c)
@@ -82,7 +82,7 b' class AdminSettingsView(BaseAppView):'
82 82 if k == '/':
83 83 k = 'root_path'
84 84
85 if k in ['push_ssl', 'publish', 'enabled']:
85 if k in ['publish', 'enabled']:
86 86 v = str2bool(v)
87 87
88 88 if k.find('.') != -1:
@@ -164,7 +164,6 b' class AdminSettingsView(BaseAppView):'
164 164 return Response(html)
165 165
166 166 try:
167 model.update_global_ssl_setting(form_result['web_push_ssl'])
168 167 model.update_global_hook_settings(form_result)
169 168
170 169 model.create_or_update_global_svn_settings(form_result)
@@ -52,7 +52,8 b' def sanitize_settings_and_apply_defaults'
52 52 default=False,
53 53 parser='bool')
54 54
55 logging_conf = jn(os.path.dirname(global_config.get('__file__')), 'logging.ini')
55 ini_loc = os.path.dirname(global_config.get('__file__'))
56 logging_conf = jn(ini_loc, 'logging.ini')
56 57 settings_maker.enable_logging(logging_conf, level='INFO' if debug_enabled else 'DEBUG')
57 58
58 59 # Default includes, possible to change as a user
@@ -95,6 +96,11 b' def sanitize_settings_and_apply_defaults'
95 96 settings_maker.make_setting('gzip_responses', False, parser='bool')
96 97 settings_maker.make_setting('startup.import_repos', 'false', parser='bool')
97 98
99 # License settings.
100 settings_maker.make_setting('license.hide_license_info', False, parser='bool')
101 settings_maker.make_setting('license.import_path', jn(ini_loc, 'rhodecode_enterprise.license'))
102 settings_maker.make_setting('license.import_path_mode', 'if-missing')
103
98 104 # statsd
99 105 settings_maker.make_setting('statsd.enabled', False, parser='bool')
100 106 settings_maker.make_setting('statsd.statsd_host', 'statsd-exporter', parser='string')
@@ -50,7 +50,7 b' from rhodecode.lib.utils2 import Attribu'
50 50 from rhodecode.lib.exc_tracking import store_exception, format_exc
51 51 from rhodecode.subscribers import (
52 52 scan_repositories_if_enabled, write_js_routes_if_enabled,
53 write_metadata_if_needed, write_usage_data)
53 write_metadata_if_needed, write_usage_data, import_license_if_present)
54 54 from rhodecode.lib.statsd_client import StatsdClient
55 55
56 56 log = logging.getLogger(__name__)
@@ -400,7 +400,8 b' def includeme(config, auth_resources=Non'
400 400 pyramid.events.ApplicationCreated)
401 401 config.add_subscriber(write_js_routes_if_enabled,
402 402 pyramid.events.ApplicationCreated)
403
403 config.add_subscriber(import_license_if_present,
404 pyramid.events.ApplicationCreated)
404 405
405 406 # Set the default renderer for HTML templates to mako.
406 407 config.add_mako_renderer('.html')
@@ -570,7 +570,6 b' class DbManage(object):'
570 570 self.create_ui_settings(path)
571 571
572 572 ui_config = [
573 ('web', 'push_ssl', 'False'),
574 573 ('web', 'allow_archive', 'gz zip bz2'),
575 574 ('web', 'allow_push', '*'),
576 575 ('web', 'baseurl', '/'),
@@ -339,21 +339,6 b' class SimpleVCS(object):'
339 339 log.exception('Failed to read http scheme')
340 340 return 'http'
341 341
342 def _check_ssl(self, environ, start_response):
343 """
344 Checks the SSL check flag and returns False if SSL is not present
345 and required True otherwise
346 """
347 org_proto = environ['wsgi._org_proto']
348 # check if we have SSL required ! if not it's a bad request !
349 require_ssl = str2bool(self.repo_vcs_config.get('web', 'push_ssl'))
350 if require_ssl and org_proto == 'http':
351 log.debug(
352 'Bad request: detected protocol is `%s` and '
353 'SSL/HTTPS is required.', org_proto)
354 return False
355 return True
356
357 342 def _get_default_cache_ttl(self):
358 343 # take AUTH_CACHE_TTL from the `rhodecode` auth plugin
359 344 plugin = loadplugin('egg:rhodecode-enterprise-ce#rhodecode')
@@ -373,12 +358,6 b' class SimpleVCS(object):'
373 358 meta.Session.remove()
374 359
375 360 def _handle_request(self, environ, start_response):
376 if not self._check_ssl(environ, start_response):
377 reason = ('SSL required, while RhodeCode was unable '
378 'to detect this as SSL request')
379 log.debug('User not allowed to proceed, %s', reason)
380 return HTTPNotAcceptable(reason)(environ, start_response)
381
382 361 if not self.url_repo_name:
383 362 log.warning('Repository name is empty: %s', self.url_repo_name)
384 363 # failed to get repo name, we fail now
@@ -159,11 +159,18 b' def detect_vcs_request(environ, backends'
159 159 # favicon often requested by browsers
160 160 'favicon.ico',
161 161
162 # static files no detection
163 '_static++',
164
165 # debug-toolbar
166 '_debug_toolbar++',
167
162 168 # e.g /_file_store/download
163 169 '_file_store++',
164 170
165 171 # login
166 "_admin/login",
172 f"{ADMIN_PREFIX}/login",
173 f"{ADMIN_PREFIX}/logout",
167 174
168 175 # 2fa
169 176 f"{ADMIN_PREFIX}/check_2fa",
@@ -178,12 +185,6 b' def detect_vcs_request(environ, backends'
178 185 # _admin/my_account is safe too
179 186 f'{ADMIN_PREFIX}/my_account++',
180 187
181 # static files no detection
182 '_static++',
183
184 # debug-toolbar
185 '_debug_toolbar++',
186
187 188 # skip ops ping, status
188 189 f'{ADMIN_PREFIX}/ops/ping',
189 190 f'{ADMIN_PREFIX}/ops/status',
@@ -193,11 +194,14 b' def detect_vcs_request(environ, backends'
193 194
194 195 '++/repo_creating_check'
195 196 ]
197
196 198 path_info = get_path_info(environ)
197 199 path_url = path_info.lstrip('/')
198 200 req_method = environ.get('REQUEST_METHOD')
199 201
200 202 for item in white_list:
203 item = item.lstrip('/')
204
201 205 if item.endswith('++') and path_url.startswith(item[:-2]):
202 206 log.debug('path `%s` in whitelist (match:%s), skipping...', path_url, item)
203 207 return handler
@@ -108,11 +108,10 b' def command(ini_path, force_yes, user, e'
108 108 dbmanage.create_permissions()
109 109 dbmanage.populate_default_permissions()
110 110 if apply_license_key:
111 try:
112 from rc_license.models import apply_trial_license_if_missing
113 apply_trial_license_if_missing(force=True)
114 except ImportError:
115 pass
111 from rhodecode.model.license import apply_license_from_file
112 license_file_path = config.get('license.import_path')
113 if license_file_path:
114 apply_license_from_file(license_file_path, force=True)
116 115
117 116 Session().commit()
118 117
@@ -391,8 +391,7 b' def prepare_config_data(clear_session=Tr'
391 391 safe_str(setting.section), safe_str(setting.key),
392 392 safe_str(setting.value)))
393 393 if setting.key == 'push_ssl':
394 # force set push_ssl requirement to False, rhodecode
395 # handles that
394 # force set push_ssl requirement to False this is deprecated, and we must force it to False
396 395 config.append((
397 396 safe_str(setting.section), safe_str(setting.key), False))
398 397 config_getter = ConfigGet()
@@ -468,7 +468,6 b' def ApplicationUiSettingsForm(localizer)'
468 468 _ = localizer
469 469
470 470 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
471 web_push_ssl = v.StringBoolean(if_missing=False)
472 471 extensions_hggit = v.StringBoolean(if_missing=False)
473 472 new_svn_branch = v.ValidSvnPattern(localizer, section='vcs_svn_branch')
474 473 new_svn_tag = v.ValidSvnPattern(localizer, section='vcs_svn_tag')
@@ -499,7 +499,6 b' class VcsSettingsModel(object):'
499 499
500 500 SVN_BRANCH_SECTION = 'vcs_svn_branch'
501 501 SVN_TAG_SECTION = 'vcs_svn_tag'
502 SSL_SETTING = ('web', 'push_ssl')
503 502 PATH_SETTING = ('paths', '/')
504 503
505 504 def __init__(self, sa=None, repo=None):
@@ -704,10 +703,6 b' class VcsSettingsModel(object):'
704 703 # branch/tags patterns
705 704 self._create_svn_settings(self.global_settings, data)
706 705
707 def update_global_ssl_setting(self, value):
708 self._create_or_update_ui(
709 self.global_settings, *self.SSL_SETTING, value=value)
710
711 706 @assert_repo_settings
712 707 def delete_repo_svn_pattern(self, id_):
713 708 ui = self.repo_settings.UiDbModel.get(id_)
@@ -205,7 +205,7 b' def write_usage_data(event):'
205 205 return
206 206
207 207 def get_update_age(dest_file):
208 now = datetime.datetime.utcnow()
208 now = datetime.datetime.now(datetime.UTC)
209 209
210 210 with open(dest_file, 'rb') as f:
211 211 data = ext_json.json.loads(f.read())
@@ -216,10 +216,9 b' def write_usage_data(event):'
216 216
217 217 return 0
218 218
219 utc_date = datetime.datetime.utcnow()
219 utc_date = datetime.datetime.now(datetime.UTC)
220 220 hour_quarter = int(math.ceil((utc_date.hour + utc_date.minute/60.0) / 6.))
221 fname = '.rc_usage_{date.year}{date.month:02d}{date.day:02d}_{hour}.json'.format(
222 date=utc_date, hour=hour_quarter)
221 fname = f'.rc_usage_{utc_date.year}{utc_date.month:02d}{utc_date.day:02d}_{hour_quarter}.json'
223 222 ini_loc = os.path.dirname(rhodecode.CONFIG.get('__file__'))
224 223
225 224 usage_dir = os.path.join(ini_loc, '.rcusage')
@@ -314,6 +313,22 b' def write_js_routes_if_enabled(event):'
314 313 log.exception('Failed to write routes.js into %s', jsroutes_file_path)
315 314
316 315
316 def import_license_if_present(event):
317 """
318 This is subscribed to the `pyramid.events.ApplicationCreated` event. It
319 does a import license key based on a presence of the file.
320 """
321 settings = event.app.registry.settings
322
323 license_file_path = settings.get('license.import_path')
324 force = settings.get('license.import_path_mode') == 'force'
325 if license_file_path:
326 from rhodecode.model.meta import Session
327 from rhodecode.model.license import apply_license_from_file
328 apply_license_from_file(license_file_path, force=force)
329 Session().commit()
330
331
317 332 class Subscriber(object):
318 333 """
319 334 Base class for subscribers to the pyramid event system.
@@ -38,42 +38,13 b''
38 38 <h3 class="panel-title">${_('Allowed client versions')}</h3>
39 39 </div>
40 40 <div class="panel-body">
41 %if c.rhodecode_edition_id != 'EE':
42 41 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
43 42 <p>
44 43 ${_('Some outdated client versions may have security vulnerabilities. This section have rules for whitelisting versions of clients for Git, Mercurial and SVN.')}
45 44 </p>
46 %else:
47 <div class="inner form" id="container">
48 45 </div>
49 %endif
50 </div>
46
51 47
52 48 </div>
53 49
54 <script>
55 $(document).ready(function() {
56 $.ajax({
57 url: pyroutes.url('admin_security_modify_allowed_vcs_client_versions'),
58 type: 'GET',
59 success: function(response) {
60 $('#container').html(response);
61 },
62 });
63 $(document).on('submit', '#allowed_clients_form', function(event) {
64 event.preventDefault();
65 var formData = $(this).serialize();
66
67 $.ajax({
68 url: pyroutes.url('admin_security_modify_allowed_vcs_client_versions'),
69 type: 'POST',
70 data: formData,
71 success: function(response) {
72 $('#container').html(response);
73 },
74 });
75 });
76 });
77 </script>
78
79 50 </%def>
@@ -5,22 +5,7 b''
5 5
6 6 <%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, **kwargs)">
7 7 % if display_globals:
8 <div class="panel panel-default">
9 <div class="panel-heading" id="general">
10 <h3 class="panel-title">${_('General')}<a class="permalink" href="#general"></a></h3>
11 </div>
12 <div class="panel-body">
13 <div class="field">
14 <div class="checkbox">
15 ${h.checkbox('web_push_ssl' + suffix, 'True')}
16 <label for="web_push_ssl${suffix}">${_('Require SSL for vcs operations')}</label>
17 </div>
18 <div class="label">
19 <span class="help-block">${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
20 </div>
21 </div>
22 </div>
23 </div>
8
24 9 % endif
25 10
26 11 % if display_globals or repo_type in ['git', 'hg']:
@@ -120,7 +120,6 b' def test_get_config(user_util, baseapp, '
120 120
121 121 expected_config = [
122 122 ('vcs_svn_tag', 'ff89f8c714d135d865f44b90e5413b88de19a55f', '/tags/*'),
123 ('web', 'push_ssl', 'False'),
124 123 ('web', 'allow_push', '*'),
125 124 ('web', 'allow_archive', 'gz zip bz2'),
126 125 ('web', 'baseurl', '/'),
@@ -239,7 +239,6 b' class TestShadowRepoExposure(object):'
239 239 """
240 240 controller = StubVCSController(
241 241 baseapp.config.get_settings(), request_stub.registry)
242 controller._check_ssl = mock.Mock()
243 242 controller.is_shadow_repo = True
244 243 controller._action = 'pull'
245 244 controller._is_shadow_repo_dir = True
@@ -267,7 +266,6 b' class TestShadowRepoExposure(object):'
267 266 """
268 267 controller = StubVCSController(
269 268 baseapp.config.get_settings(), request_stub.registry)
270 controller._check_ssl = mock.Mock()
271 269 controller.is_shadow_repo = True
272 270 controller._action = 'pull'
273 271 controller._is_shadow_repo_dir = False
@@ -291,7 +289,6 b' class TestShadowRepoExposure(object):'
291 289 """
292 290 controller = StubVCSController(
293 291 baseapp.config.get_settings(), request_stub.registry)
294 controller._check_ssl = mock.Mock()
295 292 controller.is_shadow_repo = True
296 293 controller._action = 'push'
297 294 controller.stub_response_body = (b'dummy body value',)
@@ -578,17 +578,6 b' class TestCreateOrUpdateRepoHgSettings(o'
578 578 assert str(exc_info.value) == 'Repository is not specified'
579 579
580 580
581 class TestUpdateGlobalSslSetting(object):
582 def test_updates_global_hg_settings(self):
583 model = VcsSettingsModel()
584 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
585 model.update_global_ssl_setting('False')
586 Session().commit()
587
588 create_mock.assert_called_once_with(
589 model.global_settings, 'web', 'push_ssl', value='False')
590
591
592 581 class TestCreateOrUpdateGlobalHgSettings(object):
593 582 FORM_DATA = {
594 583 'extensions_largefiles': False,
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now