##// END OF EJS Templates
parse_qs: improved parsing of query string for obfuscation.
marcink -
r107:56be024b default
parent child Browse files
Show More
@@ -1,48 +1,57 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2016 RodeCode GmbH
2 # Copyright (C) 2014-2016 RodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
7 # (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import mock
18 import mock
19 import pytest
19 import pytest
20
20
21 from vcsserver import main
21 from vcsserver import main
22 from vcsserver.base import obfuscate_qs
22 from vcsserver.base import obfuscate_qs
23
23
24
24
25 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
25 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
26 @mock.patch('vcsserver.hgpatches.patch_largefiles_capabilities')
26 @mock.patch('vcsserver.hgpatches.patch_largefiles_capabilities')
27 def test_applies_largefiles_patch(patch_largefiles_capabilities):
27 def test_applies_largefiles_patch(patch_largefiles_capabilities):
28 main.main([])
28 main.main([])
29 patch_largefiles_capabilities.assert_called_once_with()
29 patch_largefiles_capabilities.assert_called_once_with()
30
30
31
31
32 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
32 @mock.patch('vcsserver.main.VcsServerCommand', mock.Mock())
33 @mock.patch('vcsserver.main.MercurialFactory', None)
33 @mock.patch('vcsserver.main.MercurialFactory', None)
34 @mock.patch(
34 @mock.patch(
35 'vcsserver.hgpatches.patch_largefiles_capabilities',
35 'vcsserver.hgpatches.patch_largefiles_capabilities',
36 mock.Mock(side_effect=Exception("Must not be called")))
36 mock.Mock(side_effect=Exception("Must not be called")))
37 def test_applies_largefiles_patch_only_if_mercurial_is_available():
37 def test_applies_largefiles_patch_only_if_mercurial_is_available():
38 main.main([])
38 main.main([])
39
39
40
40
41 @pytest.mark.parametrize('given, expected', [
41 @pytest.mark.parametrize('given, expected', [
42 ('bad', 'bad'),
43 ('query&foo=bar', 'query&foo=bar'),
44 ('equery&auth_token=bar', 'equery&auth_token=*****'),
45 ('a;b;c;query&foo=bar&auth_token=secret',
46 'a&b&c&query&foo=bar&auth_token=*****'),
47 ('', ''),
48 (None, None),
42 ('foo=bar', 'foo=bar'),
49 ('foo=bar', 'foo=bar'),
43 ('auth_token=secret', 'auth_token=*****'),
50 ('auth_token=secret', 'auth_token=*****'),
44 ('auth_token=secret&api_key=secret2', 'auth_token=*****&api_key=*****'),
51 ('auth_token=secret&api_key=secret2',
45 ('auth_token=secret&api_key=secret2&param=value', 'auth_token=*****&api_key=*****&param=value'),
52 'auth_token=*****&api_key=*****'),
53 ('auth_token=secret&api_key=secret2&param=value',
54 'auth_token=*****&api_key=*****&param=value'),
46 ])
55 ])
47 def test_obfuscate_qs(given, expected):
56 def test_obfuscate_qs(given, expected):
48 assert expected == obfuscate_qs(given)
57 assert expected == obfuscate_qs(given)
@@ -1,81 +1,85 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2016 RodeCode GmbH
2 # Copyright (C) 2014-2016 RodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
7 # (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import logging
18 import logging
19 import urlparse
19 import urlparse
20
20
21 log = logging.getLogger(__name__)
21 log = logging.getLogger(__name__)
22
22
23
23
24 class RepoFactory(object):
24 class RepoFactory(object):
25 """
25 """
26 Utility to create instances of repository
26 Utility to create instances of repository
27
27
28 It provides internal caching of the `repo` object based on
28 It provides internal caching of the `repo` object based on
29 the :term:`call context`.
29 the :term:`call context`.
30 """
30 """
31
31
32 def __init__(self, repo_cache):
32 def __init__(self, repo_cache):
33 self._cache = repo_cache
33 self._cache = repo_cache
34
34
35 def _create_config(self, path, config):
35 def _create_config(self, path, config):
36 config = {}
36 config = {}
37 return config
37 return config
38
38
39 def _create_repo(self, wire, create):
39 def _create_repo(self, wire, create):
40 raise NotImplementedError()
40 raise NotImplementedError()
41
41
42 def repo(self, wire, create=False):
42 def repo(self, wire, create=False):
43 """
43 """
44 Get a repository instance for the given path.
44 Get a repository instance for the given path.
45
45
46 Uses internally the low level beaker API since the decorators introduce
46 Uses internally the low level beaker API since the decorators introduce
47 significant overhead.
47 significant overhead.
48 """
48 """
49 def create_new_repo():
49 def create_new_repo():
50 return self._create_repo(wire, create)
50 return self._create_repo(wire, create)
51
51
52 return self._repo(wire, create_new_repo)
52 return self._repo(wire, create_new_repo)
53
53
54 def _repo(self, wire, createfunc):
54 def _repo(self, wire, createfunc):
55 context = wire.get('context', None)
55 context = wire.get('context', None)
56 cache = wire.get('cache', True)
56 cache = wire.get('cache', True)
57 log.debug(
57 log.debug(
58 'GET %s@%s with cache:%s. Context: %s',
58 'GET %s@%s with cache:%s. Context: %s',
59 self.__class__.__name__, wire['path'], cache, context)
59 self.__class__.__name__, wire['path'], cache, context)
60
60
61 if context and cache:
61 if context and cache:
62 cache_key = (context, wire['path'])
62 cache_key = (context, wire['path'])
63 log.debug(
63 log.debug(
64 'FETCH %s@%s repo object from cache. Context: %s',
64 'FETCH %s@%s repo object from cache. Context: %s',
65 self.__class__.__name__, wire['path'], context)
65 self.__class__.__name__, wire['path'], context)
66 return self._cache.get(key=cache_key, createfunc=createfunc)
66 return self._cache.get(key=cache_key, createfunc=createfunc)
67 else:
67 else:
68 log.debug(
68 log.debug(
69 'INIT %s@%s repo object based on wire %s. Context: %s',
69 'INIT %s@%s repo object based on wire %s. Context: %s',
70 self.__class__.__name__, wire['path'], wire, context)
70 self.__class__.__name__, wire['path'], wire, context)
71 return createfunc()
71 return createfunc()
72
72
73
73
74 def obfuscate_qs(query_string):
74 def obfuscate_qs(query_string):
75 if query_string is None:
76 return None
77
75 parsed = []
78 parsed = []
76 for k, v in urlparse.parse_qsl(query_string):
79 for k, v in urlparse.parse_qsl(query_string, keep_blank_values=True):
77 if k in ['auth_token', 'api_key']:
80 if k in ['auth_token', 'api_key']:
78 v = "*****"
81 v = "*****"
79 parsed.append((k, v))
82 parsed.append((k, v))
80
83
81 return '&'.join('{}={}'.format(k,v) for k,v in parsed)
84 return '&'.join('{}{}'.format(
85 k, '={}'.format(v) if v else '') for k, v in parsed)
General Comments 0
You need to be logged in to leave comments. Login now