Show More
@@ -0,0 +1,62 b'' | |||
|
1 | <style> | |
|
2 | .form-group { | |
|
3 | margin-bottom: 15px; | |
|
4 | } | |
|
5 | ||
|
6 | .form-group label { | |
|
7 | display: flex; | |
|
8 | align-items: left; | |
|
9 | font-weight: bold; | |
|
10 | } | |
|
11 | ||
|
12 | .form-control { | |
|
13 | width: 60%; | |
|
14 | padding: 10px; | |
|
15 | font-size: 1rem; | |
|
16 | line-height: 1.5; | |
|
17 | border: 1px solid #ced4da; | |
|
18 | border-radius: 4px; | |
|
19 | box-sizing: border-box; | |
|
20 | } | |
|
21 | ||
|
22 | .btn-primary { | |
|
23 | background-color: #007bff; | |
|
24 | border: none; | |
|
25 | padding: 10px 20px; | |
|
26 | color: white; | |
|
27 | font-size: 1rem; | |
|
28 | border-radius: 4px; | |
|
29 | cursor: pointer; | |
|
30 | } | |
|
31 | ||
|
32 | .btn-primary:hover { | |
|
33 | background-color: #0056b3; | |
|
34 | } | |
|
35 | .form-group .help_block { | |
|
36 | display: block; | |
|
37 | width: 100%; | |
|
38 | margin-top: 10px; | |
|
39 | text-align: left; | |
|
40 | font-size: 0.875rem; | |
|
41 | } | |
|
42 | </style> | |
|
43 | ||
|
44 | <div> | |
|
45 | <div class="form-group"> | |
|
46 | ${h.secure_form(h.route_path('check_2fa'), request=request, id='allowed_clients_form')} | |
|
47 | <p><label for="git">${_('git')}:</label> | |
|
48 | ${h.text('git', class_="form-control", value=initial_git)}</p> | |
|
49 | <p><label for="hg">${_('hg')}:</label> | |
|
50 | ${h.text('hg', class_="form-control", value=initial_hg)}</p> | |
|
51 | <p><label for="svn">${_('svn')}:</label> | |
|
52 | ${h.text('svn', class_="form-control", value=initial_svn)}</p> | |
|
53 | %for k, v in errors.items(): | |
|
54 | <span class="error-message">${k}: ${v}</span> | |
|
55 | <br /> | |
|
56 | %endfor | |
|
57 | <p class="help_block">${_('Set rules for allowed git, hg or svn client versions. You can set exact version (for example 2.0.9) or use comparison operators to set earliest or latest version (>=2.6.0)')}</p> | |
|
58 | ||
|
59 | ${h.submit('send', _('Save'), class_="btn btn-primary")} | |
|
60 | ${h.end_form()} | |
|
61 | </div> | |
|
62 | </div> |
@@ -49,22 +49,31 b' def admin_routes(config):' | |||
|
49 | 49 | |
|
50 | 50 | config.add_route( |
|
51 | 51 | 'admin_security', |
|
52 |
pattern= |
|
|
52 | pattern='/security') | |
|
53 | 53 | config.add_view( |
|
54 | 54 | AdminSecurityView, |
|
55 |
attr='security' |
|
|
55 | attr='security', | |
|
56 | 56 | route_name='admin_security', request_method='GET', |
|
57 | 57 | renderer='rhodecode:templates/admin/security/security.mako') |
|
58 | 58 | |
|
59 | 59 | config.add_route( |
|
60 | 60 | name='admin_security_update', |
|
61 |
pattern= |
|
|
61 | pattern='/security/update') | |
|
62 | 62 | config.add_view( |
|
63 | 63 | AdminSecurityView, |
|
64 | 64 | attr='security_update', |
|
65 | 65 | route_name='admin_security_update', request_method='POST', |
|
66 | 66 | renderer='rhodecode:templates/admin/security/security.mako') |
|
67 | 67 | |
|
68 | config.add_route( | |
|
69 | name='admin_security_modify_allowed_vcs_client_versions', | |
|
70 | pattern='/security/modify/allowed_vcs_client_versions') | |
|
71 | config.add_view( | |
|
72 | AdminSecurityView, | |
|
73 | attr='vcs_whitelisted_client_versions_edit', | |
|
74 | route_name='admin_security_modify_allowed_vcs_client_versions', request_method=('GET', 'POST'), | |
|
75 | renderer='rhodecode:templates/admin/security/edit_allowed_vcs_client_versions.mako') | |
|
76 | ||
|
68 | 77 | |
|
69 | 78 | config.add_route( |
|
70 | 79 | name='admin_audit_logs', |
@@ -17,8 +17,13 b'' | |||
|
17 | 17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
18 | 18 | |
|
19 | 19 | import logging |
|
20 | import formencode | |
|
20 | 21 | |
|
22 | from rhodecode import BACKENDS | |
|
21 | 23 | 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 | |
|
22 | 27 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
23 | 28 | |
|
24 | 29 | log = logging.getLogger(__name__) |
@@ -37,3 +42,31 b' class AdminSecurityView(BaseAppView):' | |||
|
37 | 42 | c.active = 'security' |
|
38 | 43 | return self._get_template_context(c) |
|
39 | 44 | |
|
45 | @LoginRequired() | |
|
46 | @HasPermissionAllDecorator('hg.admin') | |
|
47 | def vcs_whitelisted_client_versions_edit(self): | |
|
48 | _ = self.request.translate | |
|
49 | 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) |
@@ -102,6 +102,11 b' class HTTPRequirementError(HTTPClientErr' | |||
|
102 | 102 | self.args = (message, ) |
|
103 | 103 | |
|
104 | 104 | |
|
105 | class ClientNotSupportedError(HTTPRequirementError): | |
|
106 | title = explanation = 'Client Not Supported' | |
|
107 | reason = None | |
|
108 | ||
|
109 | ||
|
105 | 110 | class HTTPLockedRC(HTTPClientError): |
|
106 | 111 | """ |
|
107 | 112 | Special Exception For locked Repos in RhodeCode, the return code can |
@@ -30,7 +30,7 b' from rhodecode.lib import helpers as h' | |||
|
30 | 30 | from rhodecode.lib import audit_logger |
|
31 | 31 | from rhodecode.lib.utils2 import safe_str, user_agent_normalizer |
|
32 | 32 | from rhodecode.lib.exceptions import ( |
|
33 | HTTPLockedRC, HTTPBranchProtected, UserCreationError) | |
|
33 | HTTPLockedRC, HTTPBranchProtected, UserCreationError, ClientNotSupportedError) | |
|
34 | 34 | from rhodecode.model.db import Repository, User |
|
35 | 35 | from rhodecode.lib.statsd_client import StatsdClient |
|
36 | 36 | |
@@ -64,6 +64,18 b' def is_shadow_repo(extras):' | |||
|
64 | 64 | return extras['is_shadow_repo'] |
|
65 | 65 | |
|
66 | 66 | |
|
67 | def check_vcs_client(extras): | |
|
68 | """ | |
|
69 | Checks if vcs client is allowed (Only works in enterprise edition) | |
|
70 | """ | |
|
71 | try: | |
|
72 | from rc_ee.lib.security.utils import is_vcs_client_whitelisted | |
|
73 | except ModuleNotFoundError: | |
|
74 | is_vcs_client_whitelisted = lambda *x: True | |
|
75 | backend = extras.get('scm') | |
|
76 | if not is_vcs_client_whitelisted(extras.get('user_agent'), backend): | |
|
77 | raise ClientNotSupportedError(f"Your {backend} client is forbidden") | |
|
78 | ||
|
67 | 79 | def _get_scm_size(alias, root_path): |
|
68 | 80 | |
|
69 | 81 | if not alias.startswith('.'): |
@@ -108,6 +120,7 b' def pre_push(extras):' | |||
|
108 | 120 | It bans pushing when the repository is locked. |
|
109 | 121 | """ |
|
110 | 122 | |
|
123 | check_vcs_client(extras) | |
|
111 | 124 | user = User.get_by_username(extras.username) |
|
112 | 125 | output = '' |
|
113 | 126 | if extras.locked_by[0] and user.user_id != int(extras.locked_by[0]): |
@@ -180,6 +193,7 b' def pre_pull(extras):' | |||
|
180 | 193 | It bans pulling when the repository is locked. |
|
181 | 194 | """ |
|
182 | 195 | |
|
196 | check_vcs_client(extras) | |
|
183 | 197 | output = '' |
|
184 | 198 | if extras.locked_by[0]: |
|
185 | 199 | locked_by = User.get(extras.locked_by[0]).username |
@@ -84,8 +84,11 b' def adopt_for_celery(func):' | |||
|
84 | 84 | @wraps(func) |
|
85 | 85 | def wrapper(extras): |
|
86 | 86 | extras = AttributeDict(extras) |
|
87 | # HooksResponse implements to_json method which must be used there. | |
|
88 | return func(extras).to_json() | |
|
87 | try: | |
|
88 | # HooksResponse implements to_json method which must be used there. | |
|
89 | return func(extras).to_json() | |
|
90 | except Exception as e: | |
|
91 | return {'status': 128, 'exception': type(e).__name__, 'exception_args': e.args} | |
|
89 | 92 | return wrapper |
|
90 | 93 | |
|
91 | 94 |
@@ -129,6 +129,20 b' def TOTPForm(localizer, user, allow_reco' | |||
|
129 | 129 | return _TOTPForm |
|
130 | 130 | |
|
131 | 131 | |
|
132 | def WhitelistedVcsClientsForm(localizer): | |
|
133 | _ = localizer | |
|
134 | ||
|
135 | class _WhitelistedVcsClientsForm(formencode.Schema): | |
|
136 | regexp = r'^(?:\s*[<>=~^!]*\s*\d{1,2}\.\d{1,2}(?:\.\d{1,2})?\s*|\*)\s*(?:,\s*[<>=~^!]*\s*\d{1,2}\.\d{1,2}(?:\.\d{1,2})?\s*|\s*\*\s*)*$' | |
|
137 | allow_extra_fields = True | |
|
138 | filter_extra_fields = True | |
|
139 | git = v.Regex(regexp) | |
|
140 | hg = v.Regex(regexp) | |
|
141 | svn = v.Regex(regexp) | |
|
142 | ||
|
143 | return _WhitelistedVcsClientsForm | |
|
144 | ||
|
145 | ||
|
132 | 146 | def UserForm(localizer, edit=False, available_languages=None, old_data=None): |
|
133 | 147 | old_data = old_data or {} |
|
134 | 148 | available_languages = available_languages or [] |
@@ -86,6 +86,7 b' function registerRCRoutes() {' | |||
|
86 | 86 | pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []); |
|
87 | 87 | pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []); |
|
88 | 88 | pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []); |
|
89 | pyroutes.register('admin_security_modify_allowed_vcs_client_versions', '/_admin/security/modify/allowed_vcs_client_versions', []); | |
|
89 | 90 | pyroutes.register('apiv2', '/_admin/api', []); |
|
90 | 91 | pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']); |
|
91 | 92 | pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']); |
@@ -28,13 +28,52 b'' | |||
|
28 | 28 | <div class="panel-body"> |
|
29 | 29 | <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> |
|
30 | 30 | <p> |
|
31 | You can scan your repositories for exposed secrets, passwords, etc | |
|
31 | ${_('You can scan your repositories for exposed secrets, passwords, etc')} | |
|
32 | 32 | </p> |
|
33 | 33 | </div> |
|
34 | 34 | </div> |
|
35 | 35 | |
|
36 | <div class="panel panel-default"> | |
|
37 | <div class="panel-heading"> | |
|
38 | <h3 class="panel-title">${_('Allowed client versions')}</h3> | |
|
39 | </div> | |
|
40 | <div class="panel-body"> | |
|
41 | %if c.rhodecode_edition_id != 'EE': | |
|
42 | <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 | <p> | |
|
44 | ${_('Some outdated client versions may have security vulnerabilities. This section have rules for whitelisting versions of clients for Git, Mercurial and SVN.')} | |
|
45 | </p> | |
|
46 | %else: | |
|
47 | <div class="inner form" id="container"> | |
|
48 | </div> | |
|
49 | %endif | |
|
50 | </div> | |
|
51 | ||
|
36 | 52 | </div> |
|
37 | 53 | |
|
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> | |
|
38 | 78 | |
|
39 | 79 | </%def> |
|
40 |
General Comments 0
You need to be logged in to leave comments.
Login now