We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
recaptcha v1 will stop working 2018-3-31
### CKAN Version if known (or site URL)
All since 2.0ish

### The problem
Users will not be able to register, due to the re-captcha being switched off by Google on 2018-3-31.

Google's deprecation info: https://developers.google.com/recaptcha/docs/versions#v1

This affects those sites that:
* have setup recaptcha (i.e. registered with Google and [added their keys to the CKAN config](http://docs.ckan.org/en/latest/maintaining/configuration.html?highlight=captcha#ckan-recaptcha-publickey)). This is not part of the default CKAN install. Most installs only use the 'user' functionality for admins, so the impact should be limited.
* AND they use v1 of recaptcha. This is the default in the CKAN config, but Google deprecated v1 May 2016 and prevented new sites using it (I imagine it was the same time), so the issue only affects sites set-up before then.

### How to check if you have this problem
Show the relevant bits of your CKAN config:
```
grep recaptcha /etc/ckan/default/production.ini
```
IF `ckan.recaptcha.publickey` has a value (i.e. not blank or unset)
AND (`ckan.recaptcha.version = 1` OR `ckan.recaptcha.version` is blank or unset)
THEN you need to upgrade to recaptcha 2 before 2018-03-31.

### Action
I think we should change the default to v2 and warn the community.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ckan/lib/captcha.py`
Content:
```
1 # encoding: utf-8
2 
3 from ckan.common import config
4 
5 import urllib
6 import urllib2
7 import json
8 
9 def check_recaptcha(request):
10     '''Check a user\'s recaptcha submission is valid, and raise CaptchaError
11     on failure.'''
12     recaptcha_private_key = config.get('ckan.recaptcha.privatekey', '')
13     if not recaptcha_private_key:
14         # Recaptcha not enabled
15         return
16     
17     client_ip_address = request.environ.get('REMOTE_ADDR', 'Unknown IP Address')
18     
19     recaptcha_version = config.get('ckan.recaptcha.version', '1')
20     if recaptcha_version is '1':
21         recaptcha_response_field = request.params.get('recaptcha_response_field', '')
22         recaptcha_server_name = 'http://api-verify.recaptcha.net/verify'
23         recaptcha_challenge_field = request.params.get('recaptcha_challenge_field')
24 
25         # recaptcha_response_field will be unicode if there are foreign chars in
26         # the user input. So we need to encode it as utf8 before urlencoding or
27         # we get an exception (#1431).
28         params = urllib.urlencode(dict(privatekey=recaptcha_private_key,
29                                        remoteip=client_ip_address,
30                                        challenge=recaptcha_challenge_field,
31                                        response=recaptcha_response_field.encode('utf8')))
32         f = urllib2.urlopen(recaptcha_server_name, params)
33         data = f.read()
34         f.close()
35         
36         if not data.lower().startswith('true'):
37             raise CaptchaError()
38     elif recaptcha_version is '2':
39         recaptcha_response_field = request.params.get('g-recaptcha-response', '')
40         recaptcha_server_name = 'https://www.google.com/recaptcha/api/siteverify'
41 
42         # recaptcha_response_field will be unicode if there are foreign chars in
43         # the user input. So we need to encode it as utf8 before urlencoding or
44         # we get an exception (#1431).
45         params = urllib.urlencode(dict(secret=recaptcha_private_key,
46                                        remoteip=client_ip_address,
47                                        response=recaptcha_response_field.encode('utf8')))
48         f = urllib2.urlopen(recaptcha_server_name, params)
49         data = json.load(f)   
50         f.close()
51     
52         try:
53             if not data['success']:
54                 raise CaptchaError()
55         except IndexError:
56             # Something weird with recaptcha response
57             raise CaptchaError()
58 
59 class CaptchaError(ValueError):
60     pass
```

Path: `ckan/lib/app_globals.py`
Content:
```
1 # encoding: utf-8
2 
3 ''' The application's Globals object '''
4 
5 import logging
6 import time
7 from threading import Lock
8 import re
9 
10 from paste.deploy.converters import asbool
11 from ckan.common import config
12 
13 import ckan
14 import ckan.model as model
15 import ckan.logic as logic
16 from logic.schema import update_configuration_schema
17 
18 
19 log = logging.getLogger(__name__)
20 
21 
22 # mappings translate between config settings and globals because our naming
23 # conventions are not well defined and/or implemented
24 mappings = {
25 #   'config_key': 'globals_key',
26 }
27 
28 
29 # This mapping is only used to define the configuration options (from the
30 # `config` object) that should be copied to the `app_globals` (`g`) object.
31 app_globals_from_config_details = {
32     'ckan.site_title': {},
33     'ckan.site_logo': {},
34     'ckan.site_url': {},
35     'ckan.site_description': {},
36     'ckan.site_about': {},
37     'ckan.site_intro_text': {},
38     'ckan.site_custom_css': {},
39     'ckan.favicon': {}, # default gets set in config.environment.py
40     'ckan.template_head_end': {},
41     'ckan.template_footer_end': {},
42         # has been setup in load_environment():
43     'ckan.site_id': {},
44     'ckan.recaptcha.publickey': {'name': 'recaptcha_publickey'},
45     'ckan.recaptcha.version': {'name': 'recaptcha_version', 'default': '1'},
46     'ckan.template_title_deliminater': {'default': '-'},
47     'ckan.template_head_end': {},
48     'ckan.template_footer_end': {},
49     'ckan.dumps_url': {},
50     'ckan.dumps_format': {},
51     'ofs.impl': {'name': 'ofs_impl'},
52     'ckan.homepage_style': {'default': '1'},
53 
54     # split string
55     'search.facets': {'default': 'organization groups tags res_format license_id',
56                       'type': 'split',
57                       'name': 'facets'},
58     'package_hide_extras': {'type': 'split'},
59     'ckan.plugins': {'type': 'split'},
60 
61     # bool
62     'debug': {'default': 'false', 'type' : 'bool'},
63     'ckan.debug_supress_header' : {'default': 'false', 'type' : 'bool'},
64     'ckan.legacy_templates' : {'default': 'false', 'type' : 'bool'},
65     'ckan.tracking_enabled' : {'default': 'false', 'type' : 'bool'},
66 
67     # int
68     'ckan.datasets_per_page': {'default': '20', 'type': 'int'},
69     'ckan.activity_list_limit': {'default': '30', 'type': 'int'},
70     'ckan.user_list_limit': {'default': '20', 'type': 'int'},
71     'search.facets.default': {'default': '10', 'type': 'int',
72                              'name': 'facets_default_number'},
73 }
74 
75 
76 # A place to store the origional config options of we override them
77 _CONFIG_CACHE = {}
78 
79 def set_main_css(css_file):
80     ''' Sets the main_css.  The css_file must be of the form file.css '''
81     assert css_file.endswith('.css')
82     new_css = css_file
83     # FIXME we should check the css file exists
84     app_globals.main_css = str(new_css)
85 
86 
87 def set_app_global(key, value):
88     '''
89     Set a new key on the app_globals (g) object
90 
91     It will process the value according to the options on
92     app_globals_from_config_details (if any)
93     '''
94     key, value = process_app_global(key, value)
95     setattr(app_globals, key, value)
96 
97 
98 def process_app_global(key, value):
99     '''
100     Tweak a key, value pair meant to be set on the app_globals (g) object
101 
102     According to the options on app_globals_from_config_details (if any)
103     '''
104     options = app_globals_from_config_details.get(key)
105     key = get_globals_key(key)
106     if options:
107         if 'name' in options:
108             key = options['name']
109         value = value or options.get('default', '')
110 
111         data_type = options.get('type')
112         if data_type == 'bool':
113             value = asbool(value)
114         elif data_type == 'int':
115             value = int(value)
116         elif data_type == 'split':
117             value = value.split()
118 
119     return key, value
120 
121 
122 def get_globals_key(key):
123     # create our globals key
124     # these can be specified in mappings or else we remove
125     # the `ckan.` part this is to keep the existing namings
126     # set the value
127     if key in mappings:
128         return mappings[key]
129     elif key.startswith('ckan.'):
130         return key[5:]
131     else:
132         return key
133 
134 
135 def reset():
136     ''' set updatable values from config '''
137     def get_config_value(key, default=''):
138         if model.meta.engine.has_table('system_info'):
139             value = model.get_system_info(key)
140         else:
141             value = None
142         config_value = config.get(key)
143         # sort encodeings if needed
144         if isinstance(config_value, str):
145             try:
146                 config_value = config_value.decode('utf-8')
147             except UnicodeDecodeError:
148                 config_value = config_value.decode('latin-1')
149         # we want to store the config the first time we get here so we can
150         # reset them if needed
151         if key not in _CONFIG_CACHE:
152             _CONFIG_CACHE[key] = config_value
153         if value is not None:
154             log.debug('config `%s` set to `%s` from db' % (key, value))
155         else:
156             value = _CONFIG_CACHE[key]
157             if value:
158                 log.debug('config `%s` set to `%s` from config' % (key, value))
159             else:
160                 value = default
161 
162         set_app_global(key, value)
163 
164         # update the config
165         config[key] = value
166 
167         return value
168 
169     # update the config settings in auto update
170     schema = update_configuration_schema()
171     for key in schema.keys():
172         get_config_value(key)
173 
174     # custom styling
175     main_css = get_config_value('ckan.main_css', '/base/css/main.css')
176     set_main_css(main_css)
177 
178     if app_globals.site_logo:
179         app_globals.header_class = 'header-image'
180     elif not app_globals.site_description:
181         app_globals.header_class = 'header-text-logo'
182     else:
183         app_globals.header_class = 'header-text-logo-tagline'
184 
185 
186 class _Globals(object):
187 
188     ''' Globals acts as a container for objects available throughout the
189     life of the application. '''
190 
191     def __init__(self):
192         '''One instance of Globals is created during application
193         initialization and is available during requests via the
194         'app_globals' variable
195         '''
196         self._init()
197         self._config_update = None
198         self._mutex = Lock()
199 
200     def _check_uptodate(self):
201         ''' check the config is uptodate needed when several instances are
202         running '''
203         value = model.get_system_info('ckan.config_update')
204         if self._config_update != value:
205             if self._mutex.acquire(False):
206                 reset()
207                 self._config_update = value
208                 self._mutex.release()
209 
210     def _init(self):
211 
212         self.ckan_version = ckan.__version__
213         self.ckan_base_version = re.sub('[^0-9\.]', '', self.ckan_version)
214         if self.ckan_base_version == self.ckan_version:
215             self.ckan_doc_version = 'ckan-{0}'.format(self.ckan_version)
216         else:
217             self.ckan_doc_version = 'latest'
218 
219         # process the config details to set globals
220         for key in app_globals_from_config_details.keys():
221             new_key, value = process_app_global(key, config.get(key) or '')
222             setattr(self, new_key, value)
223 
224 
225 app_globals = _Globals()
226 del _Globals
227
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ckan/lib/app_globals.py b/ckan/lib/app_globals.py
--- a/ckan/lib/app_globals.py
+++ b/ckan/lib/app_globals.py
@@ -42,7 +42,6 @@
         # has been setup in load_environment():
     'ckan.site_id': {},
     'ckan.recaptcha.publickey': {'name': 'recaptcha_publickey'},
-    'ckan.recaptcha.version': {'name': 'recaptcha_version', 'default': '1'},
     'ckan.template_title_deliminater': {'default': '-'},
     'ckan.template_head_end': {},
     'ckan.template_footer_end': {},
diff --git a/ckan/lib/captcha.py b/ckan/lib/captcha.py
--- a/ckan/lib/captcha.py
+++ b/ckan/lib/captcha.py
@@ -13,48 +13,29 @@
     if not recaptcha_private_key:
         # Recaptcha not enabled
         return
-    
+
     client_ip_address = request.environ.get('REMOTE_ADDR', 'Unknown IP Address')
-    
-    recaptcha_version = config.get('ckan.recaptcha.version', '1')
-    if recaptcha_version is '1':
-        recaptcha_response_field = request.params.get('recaptcha_response_field', '')
-        recaptcha_server_name = 'http://api-verify.recaptcha.net/verify'
-        recaptcha_challenge_field = request.params.get('recaptcha_challenge_field')
-
-        # recaptcha_response_field will be unicode if there are foreign chars in
-        # the user input. So we need to encode it as utf8 before urlencoding or
-        # we get an exception (#1431).
-        params = urllib.urlencode(dict(privatekey=recaptcha_private_key,
-                                       remoteip=client_ip_address,
-                                       challenge=recaptcha_challenge_field,
-                                       response=recaptcha_response_field.encode('utf8')))
-        f = urllib2.urlopen(recaptcha_server_name, params)
-        data = f.read()
-        f.close()
-        
-        if not data.lower().startswith('true'):
-            raise CaptchaError()
-    elif recaptcha_version is '2':
-        recaptcha_response_field = request.params.get('g-recaptcha-response', '')
-        recaptcha_server_name = 'https://www.google.com/recaptcha/api/siteverify'
-
-        # recaptcha_response_field will be unicode if there are foreign chars in
-        # the user input. So we need to encode it as utf8 before urlencoding or
-        # we get an exception (#1431).
-        params = urllib.urlencode(dict(secret=recaptcha_private_key,
-                                       remoteip=client_ip_address,
-                                       response=recaptcha_response_field.encode('utf8')))
-        f = urllib2.urlopen(recaptcha_server_name, params)
-        data = json.load(f)   
-        f.close()
-    
-        try:
-            if not data['success']:
-                raise CaptchaError()
-        except IndexError:
-            # Something weird with recaptcha response
+
+    # reCAPTCHA v2
+    recaptcha_response_field = request.params.get('g-recaptcha-response', '')
+    recaptcha_server_name = 'https://www.google.com/recaptcha/api/siteverify'
+
+    # recaptcha_response_field will be unicode if there are foreign chars in
+    # the user input. So we need to encode it as utf8 before urlencoding or
+    # we get an exception (#1431).
+    params = urllib.urlencode(dict(secret=recaptcha_private_key,
+                                   remoteip=client_ip_address,
+                                   response=recaptcha_response_field.encode('utf8')))
+    f = urllib2.urlopen(recaptcha_server_name, params)
+    data = json.load(f)
+    f.close()
+
+    try:
+        if not data['success']:
             raise CaptchaError()
+    except IndexError:
+        # Something weird with recaptcha response
+        raise CaptchaError()
 
 class CaptchaError(ValueError):
-    pass
\ No newline at end of file
+    pass

{"golden_diff": "diff --git a/ckan/lib/app_globals.py b/ckan/lib/app_globals.py\n--- a/ckan/lib/app_globals.py\n+++ b/ckan/lib/app_globals.py\n@@ -42,7 +42,6 @@\n         # has been setup in load_environment():\n     'ckan.site_id': {},\n     'ckan.recaptcha.publickey': {'name': 'recaptcha_publickey'},\n-    'ckan.recaptcha.version': {'name': 'recaptcha_version', 'default': '1'},\n     'ckan.template_title_deliminater': {'default': '-'},\n     'ckan.template_head_end': {},\n     'ckan.template_footer_end': {},\ndiff --git a/ckan/lib/captcha.py b/ckan/lib/captcha.py\n--- a/ckan/lib/captcha.py\n+++ b/ckan/lib/captcha.py\n@@ -13,48 +13,29 @@\n     if not recaptcha_private_key:\n         # Recaptcha not enabled\n         return\n-    \n+\n     client_ip_address = request.environ.get('REMOTE_ADDR', 'Unknown IP Address')\n-    \n-    recaptcha_version = config.get('ckan.recaptcha.version', '1')\n-    if recaptcha_version is '1':\n-        recaptcha_response_field = request.params.get('recaptcha_response_field', '')\n-        recaptcha_server_name = 'http://api-verify.recaptcha.net/verify'\n-        recaptcha_challenge_field = request.params.get('recaptcha_challenge_field')\n-\n-        # recaptcha_response_field will be unicode if there are foreign chars in\n-        # the user input. So we need to encode it as utf8 before urlencoding or\n-        # we get an exception (#1431).\n-        params = urllib.urlencode(dict(privatekey=recaptcha_private_key,\n-                                       remoteip=client_ip_address,\n-                                       challenge=recaptcha_challenge_field,\n-                                       response=recaptcha_response_field.encode('utf8')))\n-        f = urllib2.urlopen(recaptcha_server_name, params)\n-        data = f.read()\n-        f.close()\n-        \n-        if not data.lower().startswith('true'):\n-            raise CaptchaError()\n-    elif recaptcha_version is '2':\n-        recaptcha_response_field = request.params.get('g-recaptcha-response', '')\n-        recaptcha_server_name = 'https://www.google.com/recaptcha/api/siteverify'\n-\n-        # recaptcha_response_field will be unicode if there are foreign chars in\n-        # the user input. So we need to encode it as utf8 before urlencoding or\n-        # we get an exception (#1431).\n-        params = urllib.urlencode(dict(secret=recaptcha_private_key,\n-                                       remoteip=client_ip_address,\n-                                       response=recaptcha_response_field.encode('utf8')))\n-        f = urllib2.urlopen(recaptcha_server_name, params)\n-        data = json.load(f)   \n-        f.close()\n-    \n-        try:\n-            if not data['success']:\n-                raise CaptchaError()\n-        except IndexError:\n-            # Something weird with recaptcha response\n+\n+    # reCAPTCHA v2\n+    recaptcha_response_field = request.params.get('g-recaptcha-response', '')\n+    recaptcha_server_name = 'https://www.google.com/recaptcha/api/siteverify'\n+\n+    # recaptcha_response_field will be unicode if there are foreign chars in\n+    # the user input. So we need to encode it as utf8 before urlencoding or\n+    # we get an exception (#1431).\n+    params = urllib.urlencode(dict(secret=recaptcha_private_key,\n+                                   remoteip=client_ip_address,\n+                                   response=recaptcha_response_field.encode('utf8')))\n+    f = urllib2.urlopen(recaptcha_server_name, params)\n+    data = json.load(f)\n+    f.close()\n+\n+    try:\n+        if not data['success']:\n             raise CaptchaError()\n+    except IndexError:\n+        # Something weird with recaptcha response\n+        raise CaptchaError()\n \n class CaptchaError(ValueError):\n-    pass\n\\ No newline at end of file\n+    pass\n", "issue": "recaptcha v1 will stop working 2018-3-31\n### CKAN Version if known (or site URL)\r\nAll since 2.0ish\r\n\r\n### The problem\r\nUsers will not be able to register, due to the re-captcha being switched off by Google on 2018-3-31.\r\n\r\nGoogle's deprecation info: https://developers.google.com/recaptcha/docs/versions#v1\r\n\r\nThis affects those sites that:\r\n* have setup recaptcha (i.e. registered with Google and [added their keys to the CKAN config](http://docs.ckan.org/en/latest/maintaining/configuration.html?highlight=captcha#ckan-recaptcha-publickey)). This is not part of the default CKAN install. Most installs only use the 'user' functionality for admins, so the impact should be limited.\r\n* AND they use v1 of recaptcha. This is the default in the CKAN config, but Google deprecated v1 May 2016 and prevented new sites using it (I imagine it was the same time), so the issue only affects sites set-up before then.\r\n\r\n### How to check if you have this problem\r\nShow the relevant bits of your CKAN config:\r\n```\r\ngrep recaptcha /etc/ckan/default/production.ini\r\n```\r\nIF `ckan.recaptcha.publickey` has a value (i.e. not blank or unset)\r\nAND (`ckan.recaptcha.version = 1` OR `ckan.recaptcha.version` is blank or unset)\r\nTHEN you need to upgrade to recaptcha 2 before 2018-03-31.\r\n\r\n### Action\r\nI think we should change the default to v2 and warn the community.\n", "before_files": [{"content": "# encoding: utf-8\n\nfrom ckan.common import config\n\nimport urllib\nimport urllib2\nimport json\n\ndef check_recaptcha(request):\n    '''Check a user\\'s recaptcha submission is valid, and raise CaptchaError\n    on failure.'''\n    recaptcha_private_key = config.get('ckan.recaptcha.privatekey', '')\n    if not recaptcha_private_key:\n        # Recaptcha not enabled\n        return\n    \n    client_ip_address = request.environ.get('REMOTE_ADDR', 'Unknown IP Address')\n    \n    recaptcha_version = config.get('ckan.recaptcha.version', '1')\n    if recaptcha_version is '1':\n        recaptcha_response_field = request.params.get('recaptcha_response_field', '')\n        recaptcha_server_name = 'http://api-verify.recaptcha.net/verify'\n        recaptcha_challenge_field = request.params.get('recaptcha_challenge_field')\n\n        # recaptcha_response_field will be unicode if there are foreign chars in\n        # the user input. So we need to encode it as utf8 before urlencoding or\n        # we get an exception (#1431).\n        params = urllib.urlencode(dict(privatekey=recaptcha_private_key,\n                                       remoteip=client_ip_address,\n                                       challenge=recaptcha_challenge_field,\n                                       response=recaptcha_response_field.encode('utf8')))\n        f = urllib2.urlopen(recaptcha_server_name, params)\n        data = f.read()\n        f.close()\n        \n        if not data.lower().startswith('true'):\n            raise CaptchaError()\n    elif recaptcha_version is '2':\n        recaptcha_response_field = request.params.get('g-recaptcha-response', '')\n        recaptcha_server_name = 'https://www.google.com/recaptcha/api/siteverify'\n\n        # recaptcha_response_field will be unicode if there are foreign chars in\n        # the user input. So we need to encode it as utf8 before urlencoding or\n        # we get an exception (#1431).\n        params = urllib.urlencode(dict(secret=recaptcha_private_key,\n                                       remoteip=client_ip_address,\n                                       response=recaptcha_response_field.encode('utf8')))\n        f = urllib2.urlopen(recaptcha_server_name, params)\n        data = json.load(f)   \n        f.close()\n    \n        try:\n            if not data['success']:\n                raise CaptchaError()\n        except IndexError:\n            # Something weird with recaptcha response\n            raise CaptchaError()\n\nclass CaptchaError(ValueError):\n    pass", "path": "ckan/lib/captcha.py"}, {"content": "# encoding: utf-8\n\n''' The application's Globals object '''\n\nimport logging\nimport time\nfrom threading import Lock\nimport re\n\nfrom paste.deploy.converters import asbool\nfrom ckan.common import config\n\nimport ckan\nimport ckan.model as model\nimport ckan.logic as logic\nfrom logic.schema import update_configuration_schema\n\n\nlog = logging.getLogger(__name__)\n\n\n# mappings translate between config settings and globals because our naming\n# conventions are not well defined and/or implemented\nmappings = {\n#   'config_key': 'globals_key',\n}\n\n\n# This mapping is only used to define the configuration options (from the\n# `config` object) that should be copied to the `app_globals` (`g`) object.\napp_globals_from_config_details = {\n    'ckan.site_title': {},\n    'ckan.site_logo': {},\n    'ckan.site_url': {},\n    'ckan.site_description': {},\n    'ckan.site_about': {},\n    'ckan.site_intro_text': {},\n    'ckan.site_custom_css': {},\n    'ckan.favicon': {}, # default gets set in config.environment.py\n    'ckan.template_head_end': {},\n    'ckan.template_footer_end': {},\n        # has been setup in load_environment():\n    'ckan.site_id': {},\n    'ckan.recaptcha.publickey': {'name': 'recaptcha_publickey'},\n    'ckan.recaptcha.version': {'name': 'recaptcha_version', 'default': '1'},\n    'ckan.template_title_deliminater': {'default': '-'},\n    'ckan.template_head_end': {},\n    'ckan.template_footer_end': {},\n    'ckan.dumps_url': {},\n    'ckan.dumps_format': {},\n    'ofs.impl': {'name': 'ofs_impl'},\n    'ckan.homepage_style': {'default': '1'},\n\n    # split string\n    'search.facets': {'default': 'organization groups tags res_format license_id',\n                      'type': 'split',\n                      'name': 'facets'},\n    'package_hide_extras': {'type': 'split'},\n    'ckan.plugins': {'type': 'split'},\n\n    # bool\n    'debug': {'default': 'false', 'type' : 'bool'},\n    'ckan.debug_supress_header' : {'default': 'false', 'type' : 'bool'},\n    'ckan.legacy_templates' : {'default': 'false', 'type' : 'bool'},\n    'ckan.tracking_enabled' : {'default': 'false', 'type' : 'bool'},\n\n    # int\n    'ckan.datasets_per_page': {'default': '20', 'type': 'int'},\n    'ckan.activity_list_limit': {'default': '30', 'type': 'int'},\n    'ckan.user_list_limit': {'default': '20', 'type': 'int'},\n    'search.facets.default': {'default': '10', 'type': 'int',\n                             'name': 'facets_default_number'},\n}\n\n\n# A place to store the origional config options of we override them\n_CONFIG_CACHE = {}\n\ndef set_main_css(css_file):\n    ''' Sets the main_css.  The css_file must be of the form file.css '''\n    assert css_file.endswith('.css')\n    new_css = css_file\n    # FIXME we should check the css file exists\n    app_globals.main_css = str(new_css)\n\n\ndef set_app_global(key, value):\n    '''\n    Set a new key on the app_globals (g) object\n\n    It will process the value according to the options on\n    app_globals_from_config_details (if any)\n    '''\n    key, value = process_app_global(key, value)\n    setattr(app_globals, key, value)\n\n\ndef process_app_global(key, value):\n    '''\n    Tweak a key, value pair meant to be set on the app_globals (g) object\n\n    According to the options on app_globals_from_config_details (if any)\n    '''\n    options = app_globals_from_config_details.get(key)\n    key = get_globals_key(key)\n    if options:\n        if 'name' in options:\n            key = options['name']\n        value = value or options.get('default', '')\n\n        data_type = options.get('type')\n        if data_type == 'bool':\n            value = asbool(value)\n        elif data_type == 'int':\n            value = int(value)\n        elif data_type == 'split':\n            value = value.split()\n\n    return key, value\n\n\ndef get_globals_key(key):\n    # create our globals key\n    # these can be specified in mappings or else we remove\n    # the `ckan.` part this is to keep the existing namings\n    # set the value\n    if key in mappings:\n        return mappings[key]\n    elif key.startswith('ckan.'):\n        return key[5:]\n    else:\n        return key\n\n\ndef reset():\n    ''' set updatable values from config '''\n    def get_config_value(key, default=''):\n        if model.meta.engine.has_table('system_info'):\n            value = model.get_system_info(key)\n        else:\n            value = None\n        config_value = config.get(key)\n        # sort encodeings if needed\n        if isinstance(config_value, str):\n            try:\n                config_value = config_value.decode('utf-8')\n            except UnicodeDecodeError:\n                config_value = config_value.decode('latin-1')\n        # we want to store the config the first time we get here so we can\n        # reset them if needed\n        if key not in _CONFIG_CACHE:\n            _CONFIG_CACHE[key] = config_value\n        if value is not None:\n            log.debug('config `%s` set to `%s` from db' % (key, value))\n        else:\n            value = _CONFIG_CACHE[key]\n            if value:\n                log.debug('config `%s` set to `%s` from config' % (key, value))\n            else:\n                value = default\n\n        set_app_global(key, value)\n\n        # update the config\n        config[key] = value\n\n        return value\n\n    # update the config settings in auto update\n    schema = update_configuration_schema()\n    for key in schema.keys():\n        get_config_value(key)\n\n    # custom styling\n    main_css = get_config_value('ckan.main_css', '/base/css/main.css')\n    set_main_css(main_css)\n\n    if app_globals.site_logo:\n        app_globals.header_class = 'header-image'\n    elif not app_globals.site_description:\n        app_globals.header_class = 'header-text-logo'\n    else:\n        app_globals.header_class = 'header-text-logo-tagline'\n\n\nclass _Globals(object):\n\n    ''' Globals acts as a container for objects available throughout the\n    life of the application. '''\n\n    def __init__(self):\n        '''One instance of Globals is created during application\n        initialization and is available during requests via the\n        'app_globals' variable\n        '''\n        self._init()\n        self._config_update = None\n        self._mutex = Lock()\n\n    def _check_uptodate(self):\n        ''' check the config is uptodate needed when several instances are\n        running '''\n        value = model.get_system_info('ckan.config_update')\n        if self._config_update != value:\n            if self._mutex.acquire(False):\n                reset()\n                self._config_update = value\n                self._mutex.release()\n\n    def _init(self):\n\n        self.ckan_version = ckan.__version__\n        self.ckan_base_version = re.sub('[^0-9\\.]', '', self.ckan_version)\n        if self.ckan_base_version == self.ckan_version:\n            self.ckan_doc_version = 'ckan-{0}'.format(self.ckan_version)\n        else:\n            self.ckan_doc_version = 'latest'\n\n        # process the config details to set globals\n        for key in app_globals_from_config_details.keys():\n            new_key, value = process_app_global(key, config.get(key) or '')\n            setattr(self, new_key, value)\n\n\napp_globals = _Globals()\ndel _Globals\n", "path": "ckan/lib/app_globals.py"}], "after_files": [{"content": "# encoding: utf-8\n\nfrom ckan.common import config\n\nimport urllib\nimport urllib2\nimport json\n\ndef check_recaptcha(request):\n    '''Check a user\\'s recaptcha submission is valid, and raise CaptchaError\n    on failure.'''\n    recaptcha_private_key = config.get('ckan.recaptcha.privatekey', '')\n    if not recaptcha_private_key:\n        # Recaptcha not enabled\n        return\n\n    client_ip_address = request.environ.get('REMOTE_ADDR', 'Unknown IP Address')\n\n    # reCAPTCHA v2\n    recaptcha_response_field = request.params.get('g-recaptcha-response', '')\n    recaptcha_server_name = 'https://www.google.com/recaptcha/api/siteverify'\n\n    # recaptcha_response_field will be unicode if there are foreign chars in\n    # the user input. So we need to encode it as utf8 before urlencoding or\n    # we get an exception (#1431).\n    params = urllib.urlencode(dict(secret=recaptcha_private_key,\n                                   remoteip=client_ip_address,\n                                   response=recaptcha_response_field.encode('utf8')))\n    f = urllib2.urlopen(recaptcha_server_name, params)\n    data = json.load(f)\n    f.close()\n\n    try:\n        if not data['success']:\n            raise CaptchaError()\n    except IndexError:\n        # Something weird with recaptcha response\n        raise CaptchaError()\n\nclass CaptchaError(ValueError):\n    pass\n", "path": "ckan/lib/captcha.py"}, {"content": "# encoding: utf-8\n\n''' The application's Globals object '''\n\nimport logging\nimport time\nfrom threading import Lock\nimport re\n\nfrom paste.deploy.converters import asbool\nfrom ckan.common import config\n\nimport ckan\nimport ckan.model as model\nimport ckan.logic as logic\nfrom logic.schema import update_configuration_schema\n\n\nlog = logging.getLogger(__name__)\n\n\n# mappings translate between config settings and globals because our naming\n# conventions are not well defined and/or implemented\nmappings = {\n#   'config_key': 'globals_key',\n}\n\n\n# This mapping is only used to define the configuration options (from the\n# `config` object) that should be copied to the `app_globals` (`g`) object.\napp_globals_from_config_details = {\n    'ckan.site_title': {},\n    'ckan.site_logo': {},\n    'ckan.site_url': {},\n    'ckan.site_description': {},\n    'ckan.site_about': {},\n    'ckan.site_intro_text': {},\n    'ckan.site_custom_css': {},\n    'ckan.favicon': {}, # default gets set in config.environment.py\n    'ckan.template_head_end': {},\n    'ckan.template_footer_end': {},\n        # has been setup in load_environment():\n    'ckan.site_id': {},\n    'ckan.recaptcha.publickey': {'name': 'recaptcha_publickey'},\n    'ckan.template_title_deliminater': {'default': '-'},\n    'ckan.template_head_end': {},\n    'ckan.template_footer_end': {},\n    'ckan.dumps_url': {},\n    'ckan.dumps_format': {},\n    'ofs.impl': {'name': 'ofs_impl'},\n    'ckan.homepage_style': {'default': '1'},\n\n    # split string\n    'search.facets': {'default': 'organization groups tags res_format license_id',\n                      'type': 'split',\n                      'name': 'facets'},\n    'package_hide_extras': {'type': 'split'},\n    'ckan.plugins': {'type': 'split'},\n\n    # bool\n    'debug': {'default': 'false', 'type' : 'bool'},\n    'ckan.debug_supress_header' : {'default': 'false', 'type' : 'bool'},\n    'ckan.legacy_templates' : {'default': 'false', 'type' : 'bool'},\n    'ckan.tracking_enabled' : {'default': 'false', 'type' : 'bool'},\n\n    # int\n    'ckan.datasets_per_page': {'default': '20', 'type': 'int'},\n    'ckan.activity_list_limit': {'default': '30', 'type': 'int'},\n    'ckan.user_list_limit': {'default': '20', 'type': 'int'},\n    'search.facets.default': {'default': '10', 'type': 'int',\n                             'name': 'facets_default_number'},\n}\n\n\n# A place to store the origional config options of we override them\n_CONFIG_CACHE = {}\n\ndef set_main_css(css_file):\n    ''' Sets the main_css.  The css_file must be of the form file.css '''\n    assert css_file.endswith('.css')\n    new_css = css_file\n    # FIXME we should check the css file exists\n    app_globals.main_css = str(new_css)\n\n\ndef set_app_global(key, value):\n    '''\n    Set a new key on the app_globals (g) object\n\n    It will process the value according to the options on\n    app_globals_from_config_details (if any)\n    '''\n    key, value = process_app_global(key, value)\n    setattr(app_globals, key, value)\n\n\ndef process_app_global(key, value):\n    '''\n    Tweak a key, value pair meant to be set on the app_globals (g) object\n\n    According to the options on app_globals_from_config_details (if any)\n    '''\n    options = app_globals_from_config_details.get(key)\n    key = get_globals_key(key)\n    if options:\n        if 'name' in options:\n            key = options['name']\n        value = value or options.get('default', '')\n\n        data_type = options.get('type')\n        if data_type == 'bool':\n            value = asbool(value)\n        elif data_type == 'int':\n            value = int(value)\n        elif data_type == 'split':\n            value = value.split()\n\n    return key, value\n\n\ndef get_globals_key(key):\n    # create our globals key\n    # these can be specified in mappings or else we remove\n    # the `ckan.` part this is to keep the existing namings\n    # set the value\n    if key in mappings:\n        return mappings[key]\n    elif key.startswith('ckan.'):\n        return key[5:]\n    else:\n        return key\n\n\ndef reset():\n    ''' set updatable values from config '''\n    def get_config_value(key, default=''):\n        if model.meta.engine.has_table('system_info'):\n            value = model.get_system_info(key)\n        else:\n            value = None\n        config_value = config.get(key)\n        # sort encodeings if needed\n        if isinstance(config_value, str):\n            try:\n                config_value = config_value.decode('utf-8')\n            except UnicodeDecodeError:\n                config_value = config_value.decode('latin-1')\n        # we want to store the config the first time we get here so we can\n        # reset them if needed\n        if key not in _CONFIG_CACHE:\n            _CONFIG_CACHE[key] = config_value\n        if value is not None:\n            log.debug('config `%s` set to `%s` from db' % (key, value))\n        else:\n            value = _CONFIG_CACHE[key]\n            if value:\n                log.debug('config `%s` set to `%s` from config' % (key, value))\n            else:\n                value = default\n\n        set_app_global(key, value)\n\n        # update the config\n        config[key] = value\n\n        return value\n\n    # update the config settings in auto update\n    schema = update_configuration_schema()\n    for key in schema.keys():\n        get_config_value(key)\n\n    # custom styling\n    main_css = get_config_value('ckan.main_css', '/base/css/main.css')\n    set_main_css(main_css)\n\n    if app_globals.site_logo:\n        app_globals.header_class = 'header-image'\n    elif not app_globals.site_description:\n        app_globals.header_class = 'header-text-logo'\n    else:\n        app_globals.header_class = 'header-text-logo-tagline'\n\n\nclass _Globals(object):\n\n    ''' Globals acts as a container for objects available throughout the\n    life of the application. '''\n\n    def __init__(self):\n        '''One instance of Globals is created during application\n        initialization and is available during requests via the\n        'app_globals' variable\n        '''\n        self._init()\n        self._config_update = None\n        self._mutex = Lock()\n\n    def _check_uptodate(self):\n        ''' check the config is uptodate needed when several instances are\n        running '''\n        value = model.get_system_info('ckan.config_update')\n        if self._config_update != value:\n            if self._mutex.acquire(False):\n                reset()\n                self._config_update = value\n                self._mutex.release()\n\n    def _init(self):\n\n        self.ckan_version = ckan.__version__\n        self.ckan_base_version = re.sub('[^0-9\\.]', '', self.ckan_version)\n        if self.ckan_base_version == self.ckan_version:\n            self.ckan_doc_version = 'ckan-{0}'.format(self.ckan_version)\n        else:\n            self.ckan_doc_version = 'latest'\n\n        # process the config details to set globals\n        for key in app_globals_from_config_details.keys():\n            new_key, value = process_app_global(key, config.get(key) or '')\n            setattr(self, new_key, value)\n\n\napp_globals = _Globals()\ndel _Globals\n", "path": "ckan/lib/app_globals.py"}]}