Closed
Pull request !2298 Created on Tue, 30 Apr 2019 20:44:58, by

In Mercurial 5.0 the section for permissions will be renamed from narrowhgacl to narrowacl.
This change will make rhodecode work with both, prioritizing 5.0.

Closed, Under Review
- calculated based on 4 reviewers votes
Pull request versions not available.
Pull request reviewers
TODO Comments - 0 / 0 Show resolved
No unresolved TODOs.
Time Author Commit Description
105 commits hidden, click expand to show them.
Add another comment
COMMENTS: 4 General, 0 Inline (0 Outdated)
@@ -0,0 +1,47
1 |RCE| 4.16.1 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2019-03-07
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13
14
15 General
16 ^^^^^^^
17
18 - Docs: added missing reference for the user bookmarks feature.
19
20
21 Security
22 ^^^^^^^^
23
24 - Comments: prevent from allowing to resolve TODO comments across projects. In certain
25 conditions users could resolve TODOs not belonging to the same project.
26
27
28 Performance
29 ^^^^^^^^^^^
30
31
32
33 Fixes
34 ^^^^^
35
36 - Downloads: fixed archive links from file tree view.
37 - Markdown: fixed sanitization of checkbox extensions that removed "checked" attribute.
38 - Upgrade: fixed upgrades from older versions of RhodeCode.
39 - Pull Requests: handle non-ascii branches from short branch selector via URL.
40 - Hooks: fixed again unicode problems with new pull request link generator.
41
42
43
44 Upgrade notes
45 ^^^^^^^^^^^^^
46
47 - Scheduled release addressing problems in 4.16.X releases.
@@ -0,0 +1,41
1 |RCE| 4.16.2 |RNS|
2 ------------------
3
4 Release Date
5 ^^^^^^^^^^^^
6
7 - 2019-04-02
8
9
10 New Features
11 ^^^^^^^^^^^^
12
13
14
15 General
16 ^^^^^^^
17
18
19
20 Security
21 ^^^^^^^^
22
23
24
25 Performance
26 ^^^^^^^^^^^
27
28
29
30 Fixes
31 ^^^^^
32
33 - Integrations: fixed missing template variable for fork reference checks.
34 - Permissions: fixed server error when showing permissions for user groups.
35 - Pull requests: fixed a bug in removal of multiple reviewers at once.
36
37
38 Upgrade notes
39 ^^^^^^^^^^^^^
40
41 - Scheduled release addressing problems in 4.16.X releases.
@@ -0,0 +1,19
1 # contains not directly required libraries we want to pin the version.
2
3 atomicwrites==1.2.1
4 attrs==18.2.0
5 billiard==3.5.0.3
6 chameleon==2.24
7 cffi==1.12.2
8 ecdsa==0.13
9 hupper==1.6.1
10 gnureadline==6.3.8
11 jinja2==2.9.6
12 jsonschema==2.6.0
13 pathlib2==2.3.3
14 pyramid-jinja2==2.7
15 setproctitle==1.1.10
16 scandir==1.10.0
17 tempita==0.5.2
18 vine==1.3.0
19 configparser==3.7.4 No newline at end of file
@@ -0,0 +1,93
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import pytest
22 from rhodecode.tests import HG_REPO
23 from rhodecode.api.tests.utils import (
24 build_data, api_call, assert_error, assert_ok)
25
26
27 @pytest.mark.usefixtures("testuser_api", "app")
28 class TestApiSearch(object):
29
30 @pytest.mark.parametrize("query, expected_hits, expected_paths", [
31 ('todo', 23, [
32 'vcs/backends/hg/inmemory.py',
33 'vcs/tests/test_git.py']),
34 ('extension:rst installation', 6, [
35 'docs/index.rst',
36 'docs/installation.rst']),
37 ('def repo', 87, [
38 'vcs/tests/test_git.py',
39 'vcs/tests/test_changesets.py']),
40 ('repository:%s def test' % HG_REPO, 18, [
41 'vcs/tests/test_git.py',
42 'vcs/tests/test_changesets.py']),
43 ('"def main"', 9, [
44 'vcs/__init__.py',
45 'vcs/tests/__init__.py',
46 'vcs/utils/progressbar.py']),
47 ('owner:test_admin', 358, [
48 'vcs/tests/base.py',
49 'MANIFEST.in',
50 'vcs/utils/termcolors.py',
51 'docs/theme/ADC/static/documentation.png']),
52 ('owner:test_admin def main', 72, [
53 'vcs/__init__.py',
54 'vcs/tests/test_utils_filesize.py',
55 'vcs/tests/test_cli.py']),
56 ('owner:michał test', 0, []),
57 ])
58 def test_search_content_results(self, query, expected_hits, expected_paths):
59 id_, params = build_data(
60 self.apikey_regular, 'search',
61 search_query=query,
62 search_type='content')
63
64 response = api_call(self.app, params)
65 json_response = response.json
66
67 assert json_response['result']['item_count'] == expected_hits
68 paths = [x['f_path'] for x in json_response['result']['results']]
69
70 for expected_path in expected_paths:
71 assert expected_path in paths
72
73 @pytest.mark.parametrize("query, expected_hits, expected_paths", [
74 ('readme.rst', 3, []),
75 ('test*', 75, []),
76 ('*model*', 1, []),
77 ('extension:rst', 48, []),
78 ('extension:rst api', 24, []),
79 ])
80 def test_search_file_paths(self, query, expected_hits, expected_paths):
81 id_, params = build_data(
82 self.apikey_regular, 'search',
83 search_query=query,
84 search_type='path')
85
86 response = api_call(self.app, params)
87 json_response = response.json
88
89 assert json_response['result']['item_count'] == expected_hits
90 paths = [x['f_path'] for x in json_response['result']['results']]
91
92 for expected_path in expected_paths:
93 assert expected_path in paths
@@ -0,0 +1,112
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21
22 import logging
23
24 from rhodecode.api import jsonrpc_method
25 from rhodecode.api.exc import JSONRPCValidationError
26 from rhodecode.api.utils import Optional
27 from rhodecode.lib.index import searcher_from_config
28 from rhodecode.model import validation_schema
29 from rhodecode.model.validation_schema.schemas import search_schema
30
31 log = logging.getLogger(__name__)
32
33
34 @jsonrpc_method()
35 def search(request, apiuser, search_query, search_type, page_limit=Optional(10),
36 page=Optional(1), search_sort=Optional('newfirst'),
37 repo_name=Optional(None), repo_group_name=Optional(None)):
38 """
39 Fetch Full Text Search results using API.
40
41 :param apiuser: This is filled automatically from the |authtoken|.
42 :type apiuser: AuthUser
43 :param search_query: Search query.
44 :type search_query: str
45 :param search_type: Search type. The following are valid options:
46 * commit
47 * content
48 * path
49 :type search_type: str
50 :param page_limit: Page item limit, from 1 to 500. Default 10 items.
51 :type page_limit: Optional(int)
52 :param page: Page number. Default first page.
53 :type page: Optional(int)
54 :param search_sort: Search sort order. Default newfirst. The following are valid options:
55 * newfirst
56 * oldfirst
57 :type search_sort: Optional(str)
58 :param repo_name: Filter by one repo. Default is all.
59 :type repo_name: Optional(str)
60 :param repo_group_name: Filter by one repo group. Default is all.
61 :type repo_group_name: Optional(str)
62 """
63
64 data = {'execution_time': ''}
65 repo_name = Optional.extract(repo_name)
66 repo_group_name = Optional.extract(repo_group_name)
67
68 schema = search_schema.SearchParamsSchema()
69
70 try:
71 search_params = schema.deserialize(
72 dict(search_query=search_query,
73 search_type=search_type,
74 search_sort=Optional.extract(search_sort),
75 page_limit=Optional.extract(page_limit),
76 requested_page=Optional.extract(page))
77 )
78 except validation_schema.Invalid as err:
79 raise JSONRPCValidationError(colander_exc=err)
80
81 search_query = search_params.get('search_query')
82 search_type = search_params.get('search_type')
83 search_sort = search_params.get('search_sort')
84
85 if search_params.get('search_query'):
86 page_limit = search_params['page_limit']
87 requested_page = search_params['requested_page']
88
89 searcher = searcher_from_config(request.registry.settings)
90
91 try:
92 search_result = searcher.search(
93 search_query, search_type, apiuser, repo_name, repo_group_name,
94 requested_page=requested_page, page_limit=page_limit, sort=search_sort)
95
96 data.update(dict(
97 results=list(search_result['results']), page=requested_page,
98 item_count=search_result['count'],
99 items_per_page=page_limit))
100 finally:
101 searcher.cleanup()
102
103 if not search_result['error']:
104 data['execution_time'] = '%s results (%.3f seconds)' % (
105 search_result['count'],
106 search_result['runtime'])
107 else:
108 node = schema['search_query']
109 raise JSONRPCValidationError(
110 colander_exc=validation_schema.Invalid(node, search_result['error']))
111
112 return data
@@ -0,0 +1,54
1 # -*- coding: utf-8 -*-
2
3 import logging
4
5 from alembic.migration import MigrationContext
6 from alembic.operations import Operations
7 from sqlalchemy import String, Column
8 from sqlalchemy.sql import text
9
10 from rhodecode.lib.dbmigrate.versions import _reset_base
11 from rhodecode.model import meta, init_model_encryption
12 from rhodecode.model.db import RepoGroup
13
14
15 log = logging.getLogger(__name__)
16
17
18 def upgrade(migrate_engine):
19 """
20 Upgrade operations go here.
21 Don't create your own engine; bind migrate_engine to your metadata
22 """
23 _reset_base(migrate_engine)
24 from rhodecode.lib.dbmigrate.schema import db_4_16_0_2
25
26 init_model_encryption(db_4_16_0_2)
27
28 context = MigrationContext.configure(migrate_engine.connect())
29 op = Operations(context)
30
31 repo_group = db_4_16_0_2.RepoGroup.__table__
32
33 with op.batch_alter_table(repo_group.name) as batch_op:
34 batch_op.add_column(
35 Column("repo_group_name_hash", String(1024), nullable=True, unique=False))
36
37 _generate_repo_group_name_hashes(db_4_16_0_2, op, meta.Session)
38
39
40 def downgrade(migrate_engine):
41 pass
42
43
44 def _generate_repo_group_name_hashes(models, op, session):
45 repo_groups = models.RepoGroup.get_all()
46 for repo_group in repo_groups:
47 print(repo_group.group_name)
48 hash_ = RepoGroup.hash_repo_group_name(repo_group.group_name)
49 params = {'hash': hash_, 'id': repo_group.group_id}
50 query = text(
51 'UPDATE groups SET repo_group_name_hash = :hash'
52 ' WHERE group_id = :id').bindparams(**params)
53 op.execute(query)
54 session().commit()
@@ -0,0 +1,39
1 # -*- coding: utf-8 -*-
2
3 import logging
4
5 from alembic.migration import MigrationContext
6 from alembic.operations import Operations
7
8 from rhodecode.lib.dbmigrate.versions import _reset_base
9 from rhodecode.model import init_model_encryption
10
11
12 log = logging.getLogger(__name__)
13
14
15 def upgrade(migrate_engine):
16 """
17 Upgrade operations go here.
18 Don't create your own engine; bind migrate_engine to your metadata
19 """
20 _reset_base(migrate_engine)
21 from rhodecode.lib.dbmigrate.schema import db_4_16_0_2
22
23 init_model_encryption(db_4_16_0_2)
24
25 context = MigrationContext.configure(migrate_engine.connect())
26 op = Operations(context)
27
28 repo_group = db_4_16_0_2.RepoGroup.__table__
29
30 with op.batch_alter_table(repo_group.name) as batch_op:
31 batch_op.alter_column("repo_group_name_hash", nullable=False)
32
33
34 def downgrade(migrate_engine):
35 pass
36
37
38 def _generate_repo_group_name_hashes(models, op, session):
39 pass
@@ -0,0 +1,69
1 import os
2 import base64
3 from cryptography.fernet import Fernet, InvalidToken
4 from cryptography.hazmat.backends import default_backend
5 from cryptography.hazmat.primitives import hashes
6 from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
7
8
9 class Encryptor(object):
10 key_format = 'enc2$salt:{}$data:{}'
11 pref_len = 5 # salt:, data:
12
13 def __init__(self, enc_key):
14 self.enc_key = enc_key
15
16 def b64_encode(self, data):
17 return base64.urlsafe_b64encode(data)
18
19 def b64_decode(self, data):
20 return base64.urlsafe_b64decode(data)
21
22 def get_encryptor(self, salt):
23 """
24 Uses Fernet as encryptor with HMAC signature
25 :param salt: random salt used for encrypting the data
26 """
27 kdf = PBKDF2HMAC(
28 algorithm=hashes.SHA512(),
29 length=32,
30 salt=salt,
31 iterations=100000,
32 backend=default_backend()
33 )
34 key = self.b64_encode(kdf.derive(self.enc_key))
35 return Fernet(key)
36
37 def _get_parts(self, enc_data):
38 parts = enc_data.split('$', 3)
39 if len(parts) != 3:
40 raise ValueError('Encrypted Data has invalid format, expected {}'.format(self.key_format))
41 prefix, salt, enc_data = parts
42
43 try:
44 salt = self.b64_decode(salt[self.pref_len:])
45 except TypeError:
46 # bad base64
47 raise ValueError('Encrypted Data salt invalid format, expected base64 format')
48
49 enc_data = enc_data[self.pref_len:]
50 return prefix, salt, enc_data
51
52 def encrypt(self, data):
53 salt = os.urandom(64)
54 encryptor = self.get_encryptor(salt)
55 enc_data = encryptor.encrypt(data)
56 return self.key_format.format(self.b64_encode(salt), enc_data)
57
58 def decrypt(self, data, safe=True):
59 parts = self._get_parts(data)
60 salt = parts[1]
61 enc_data = parts[2]
62 encryptor = self.get_encryptor(salt)
63 try:
64 return encryptor.decrypt(enc_data)
65 except (InvalidToken,):
66 if safe:
67 return ''
68 else:
69 raise
@@ -1,5 +1,5
1 [bumpversion]
1 [bumpversion]
2 current_version = 4.16.0
2 current_version = 4.17.0
3 message = release: Bump version {current_version} to {new_version}
3 message = release: Bump version {current_version} to {new_version}
4
4
5 [bumpversion:file:rhodecode/VERSION]
5 [bumpversion:file:rhodecode/VERSION]
@@ -49,3 +49,6
49 4b34ce0d2c3c10510626b3b65044939bb7a2cddf v4.15.0
49 4b34ce0d2c3c10510626b3b65044939bb7a2cddf v4.15.0
50 14502561d22e6b70613674cd675ae9a604b7989f v4.15.1
50 14502561d22e6b70613674cd675ae9a604b7989f v4.15.1
51 4aaa40b605b01af78a9f6882eca561c54b525ef0 v4.15.2
51 4aaa40b605b01af78a9f6882eca561c54b525ef0 v4.15.2
52 797744642eca86640ed20bef2cd77445780abaec v4.16.0
53 6c3452c7c25ed35ff269690929e11960ed6ad7d3 v4.16.1
54 5d8057df561c4b6b81b6401aed7d2f911e6e77f7 v4.16.2
@@ -53,3 +53,12
53
53
54 generate-pkgs:
54 generate-pkgs:
55 nix-shell pkgs/shell-generate.nix --command "pip2nix generate --licenses"
55 nix-shell pkgs/shell-generate.nix --command "pip2nix generate --licenses"
56
57 generate-js-pkgs:
58 rm -rf node_modules && \
59 nix-shell pkgs/shell-generate.nix --command "node2nix --input package.json -o pkgs/node-packages.nix -e pkgs/node-env.nix -c pkgs/node-default.nix -d --flatten --nodejs-8" && \
60 sed -i -e 's/http:\/\//https:\/\//g' pkgs/node-packages.nix
61
62 generate-license-meta:
63 nix-build pkgs/license-generate.nix -o result-license && \
64 cat result-license/licenses.json | python -m json.tool > rhodecode/config/licenses.json No newline at end of file
@@ -133,6 +133,11
133 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
133 ## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
134 #rhodecode.encrypted_values.strict = false
134 #rhodecode.encrypted_values.strict = false
135
135
136 ## Pick algorithm for encryption. Either fernet (more secure) or aes (default)
137 ## fernet is safer, and we strongly recommend switching to it.
138 ## Due to backward compatibility aes is used as default.
139 #rhodecode.encrypted_values.algorithm = fernet
140
136 ## return gzipped responses from RhodeCode (static files/application)
141 ## return gzipped responses from RhodeCode (static files/application)
137 gzip_responses = false
142 gzip_responses = false
138
143
@@ -374,6 +379,10
374 beaker.session.type = file
379 beaker.session.type = file
375 beaker.session.data_dir = %(here)s/data/sessions
380 beaker.session.data_dir = %(here)s/data/sessions
376
381