Is there an easy way to adapt the django-recaptcha plugin for using the new google re-captcha API?
I already changed the template and the captcha gets displayed in the write way but the validation is not working. Has anybody an idea how I can fix this in an easy way?
Or make your own: here is mine that i made using others as a template/starting point.
import json
import urllib2, urllib
API_SERVER = "https://www.google.com/recaptcha/api/siteverify"
class RecaptchaResponse(object):
def __init__(self, is_valid, error_code=None):
self.is_valid = is_valid
self.error_code = error_code
def __unicode__(self):
print "%s, %s" % (self.is_valid, self.error_code)
def __str__(self):
return self.__unicode__()
def get_error(self):
if self.error_code and len(self.error_code):
return self.error_code[0]
def submit(recaptcha_secret, recaptcha_response, remoteip=''):
if not (recaptcha_secret and recaptcha_response and len(recaptcha_secret) and len(recaptcha_response) ):
return RecaptchaResponse(is_valid=False, error_code='incorrect-captcha-sol')
def encode_if_necessary(s):
if isinstance(s, unicode):
return s.encode('utf-8')
return s
params = urllib.urlencode({
'secret': encode_if_necessary(recaptcha_secret),
'response': encode_if_necessary(recaptcha_response),
'remoteip': encode_if_necessary(remoteip)
})
request = urllib2.Request(
url=API_SERVER,
data=params,
headers={
"Content-type": "application/x-www-form-urlencoded",
"User-agent": "reCAPTCHA Python"
}
)
httpresp = urllib2.urlopen(request)
return_values = json.loads(httpresp.read())
print return_values
if return_values.get('success', False):
return RecaptchaResponse(is_valid=True)
else:
return RecaptchaResponse(is_valid=False, error_code=return_values.get('error-codes', ''))
Same code ported to Python 3. We are using it in production. If you preffer, can be dowloaded from pypi/pip.
'''
NO-CAPTCHA VERSION: 1.0
PYTHON VERSION: 3.x
'''
import json
from urllib.request import Request, urlopen
from urllib.parse import urlencode
VERIFY_SERVER = "www.google.com"
class RecaptchaResponse(object):
def __init__(self, is_valid, error_code=None):
self.is_valid = is_valid
self.error_code = error_code
def __repr__(self):
return "Recaptcha response: %s %s" % (
self.is_valid, self.error_code)
def __str__(self):
return self.__repr__()
def displayhtml(site_key, language=''):
"""Gets the HTML to display for reCAPTCHA
site_key -- The site key
language -- The language code for the widget.
"""
return """<script src="https://www.google.com/recaptcha/api.js?hl=%(LanguageCode)s" async="async" defer="defer"></script>
<div class="g-recaptcha" data-sitekey="%(SiteKey)s"></div>
""" % {
'LanguageCode': language,
'SiteKey': site_key,
}
def submit(response,
secret_key,
remote_ip,
verify_server=VERIFY_SERVER):
"""
Submits a reCAPTCHA request for verification. Returns RecaptchaResponse
for the request
response -- The value of response from the form
secret_key -- your reCAPTCHA secret key
remote_ip -- the user's ip address
"""
if not(response and len(response)):
return RecaptchaResponse(is_valid=False, error_code='incorrect-captcha-sol')
def encode_if_necessary(s):
if isinstance(s, str):
return s.encode('utf-8')
return s
params = urlencode({
'secret': encode_if_necessary(secret_key),
'remoteip': encode_if_necessary(remote_ip),
'response': encode_if_necessary(response),
})
params = params.encode('utf-8')
request = Request(
url="https://%s/recaptcha/api/siteverify" % verify_server,
data=params,
headers={
"Content-type": "application/x-www-form-urlencoded",
"User-agent": "reCAPTCHA Python"
}
)
httpresp = urlopen(request)
return_values = json.loads(httpresp.read().decode('utf-8'))
httpresp.close()
return_code = return_values['success']
if return_code:
return RecaptchaResponse(is_valid=True)
else:
return RecaptchaResponse(is_valid=False, error_code=return_values['error-codes'])
I know your question is old, but Nowadays, you just have to write in settings.py:
NOCAPTCHA = True
And that's it.
Related
I'm trying to figure out how to mock my request for a bearer token in python.
I have a class:
class grab_apitokens(object):
def __init__(self, consumer_key, first_api_url, second_api_user, second_api_password, second_api_url):
self.consumer_key = consumer_key
self.second_api_user = second_api_user
self.second_api_password = second_api_password
self.first_api_url = first_api_url
self.second_api_url = second_api_url
def logintofirstsite(self):
b64val = base64.b64encode(self.consumer_key.encode()).decode()
headers = {"Authorization": "Basic %s" % b64val}
data = {'grant_type': 'client_credentials', 'validity_period': '3600'}
try:
response = requests.post(self.first_api_url, headers=headers, data=data)
decodedresponse = json.loads(response.content.decode())
access_token = decodedresponse['access_token']
return access_token
except:
return None
def logintosecondsite(self):
header = {"accept": "application/json", "Content-Type": "application/x-www-form-urlencoded"}
logindata = {'grant_type': 'password',
'username': "" + self.second_api_user + "", 'password': "" + self.second_api_password + ""
}
try:
returnedfromsite = requests.post(self.second_api_url + '/api/V1/token',
headers=header, data=logindata)
return returnedfromsite.json()['access_token']
except:
return None
What I can't figure out is how to mock that requests call and what it would look like in Python.
My test currently looks like:
class MyTestCase(unittest.TestCase):
def setUp(self) -> None: # PROBLEM BEGINS HERE
self.grab_apitokens = grab_apitokens(actual_key, actual_site1, actual_user, actual_pass, actual_2nd_site)
#patch('grab_apitokens.requests.get')
def test_login(self, mock_get):
mock_get.return_value.ok = True
response = self.grab_apitokens.logintosite()
assert_is_not_none(response)
# self.assertEqual(True, False)
if __name__ == '__main__':
unittest.main()
How would I mock the requests.post functionality?
With the help of a good mentor I figured out that my approach was all wrong. Here's what I ended up with for the unit test:
class MyTestCase(unittest.TestCase):
def setUp(self) -> None:
self.grab_apitokens = grab_apitokens("complete","gibberish","it really doesnt","matter","what is","in","here")
#patch('grab_apitokens.requests.posts')
def test_login(self, mock_get):
mock_json = {'token': 'foo'}
mock_get.return_value = Mock(ok=True)
mock_get.return_value.json.return_value = mock_json
mock_get.return_value.content = b'{"token": "foo"}'
response = self.grab_apitokens.logintofirstsite()
assert_equal(response, "foo")
if __name__ == '__main_
To understand what this does, I needed to know that what we're really mocking isn't the method logintofirstsite(), we're mocking the response that requests.post is making in the method. With mock_get, we're inject requests.posts to always be: {'token': 'foo'} . So everything after
response = requests.post(self.first_api_url, headers=headers, data=data)
in logintofirstsite() is what I'm really testing. Which is:
decodedresponse = json.loads(response.content.decode())
access_token = decodedresponse['token']
return access_token
The setup before the requests.post call doesn't matter one bit. Since with {'token': 'foo'} is what my requests.post call returns, the returned value after that bit of logic is 'foo', and so the assert_equal back in MyTestCase passes.
I'm trying to connect via json-rpc to the trytond isntance using this class
class HttpClient:
"""HTTP Client to make JSON RPC requests to Tryton server.
User is logged in when an object is created.
"""
def __init__(self, url, database_name, user, passwd):
self._url = '{}/{}/'.format(url, database_name)
self._user = user
self._passwd = passwd
self._login()
self._id = 0
def get_id(self):
self._id += 1
return self._id
def _login(self):
"""
Returns list, where
0 - user id
1 - session token
"""
payload = json.dumps({
'params': [self._user, {'password': self._passwd}],
'jsonrpc': "2.0",
'method': 'common.db.login',
'id': 1,
})
headers = {'content-type': 'application/json'}
result = requests.post(self._url, data=payload, headers=headers)
if result.status_code in [500, 401]:
raise Exception(result.text)
if 'json' in result:
self._session = result.json()['result']
else:
self._session = json.loads(result.text)
return self._session
def call(self, prefix, method, params=[[], {}]):
"""RPC Call
"""
method = '{}.{}'.format(prefix, method)
payload = json.dumps({
'params': params,
'method': method,
'id': self.get_id(),
})
authorization = base64.b64encode(self._session[1].encode('utf-8'))
headers = {
'Content-Type': 'application/json',
'Authorization': b'Session ' + authorization
}
response = requests.post(self._url, data=payload, headers=headers)
if response.status_code in [500, 401]:
raise Exception(response.text)
return response.json()
def model(self, model, method, args=[], kwargs={}):
return self.call('model.%s' % model, method, [args, kwargs])
def system(self, method):
return self.call('system', method, params=[])
and I call it in this way
def notifieToMainServer(self):
url = "http://%s:%s" % (HOST, PORT)
headers = {'content-type': 'application/json'}
client = HttpClient(url, "tryton", CREDENTIALS[0], CREDENTIALS[1])
client.model('main.register',
'ActivateService',
{'code': self.code,
'name': self.nome,
'surname': self.cognome,
'service_type': 'registry',
'service_url': '' # qui andra messa l'url di chimata
}
)
the creatin of the HttpClient works well and I'm able to login, but when I try to call the method ActivateService I recive a 401 responce.
I also add the ActivateService into the rpc class
#classmethod
def __setup__(cls):
super(MainRegister, cls).__setup__()
cls.__rpc__.update({
'ActivateService': RPC(instantiate=0)})
and the function is like
def ActivateService(self,
code,
name,
surname,
service_type,
service_url):
"""
activate the service for the given code and the given service
"""
what I did wrong ?
best regards,
Matteo
The Authorization header should be:
'Authorization': : b'Bearer ' + authorization
At the and I finally solve the problem with this modifies class
class HttpClient:
"""HTTP Client to make JSON RPC requests to Tryton server.
User is logged in when an object is created.
"""
def __init__(self, url, database_name, user, passwd):
self._url = '{}/{}/'.format(url, database_name)
self._user = user
self._passwd = passwd
self._login()
self._id = 0
def get_id(self):
self._id += 1
return self._id
def _login(self):
"""
Returns list, where
0 - user id
1 - session token
"""
payload = json.dumps({
'params': [self._user, {'password': self._passwd}],
'jsonrpc': "2.0",
'method': 'common.db.login',
'id': 1,
})
headers = {'content-type': 'application/json'}
result = requests.post(self._url,
data=payload,
headers=headers)
if result.status_code in [500, 401]:
raise Exception(result.text)
if 'json' in result:
self._session = result.json()['result']
else:
self._session = json.loads(result.text)
return self._session
def call(self, prefix, method, params=[[], {}, {}]):
"""RPC Call
"""
method = '{}.{}'.format(prefix, method)
payload = json.dumps({
'params': params,
'method': method,
'id': self.get_id(),
})
auth = "%s:%s:%s" % (self._user, self._session[0], self._session[1])
authorization = base64.b64encode(auth.encode('utf-8'))
headers = {
'Content-Type': 'application/json',
'Authorization': b'Session ' + authorization
}
response = requests.post(self._url,
data=payload,
headers=headers)
if response.status_code in [500, 401]:
raise Exception(response.text)
return response.json()
def model(self, model, method, args=[], kwargs={}):
return self.call('model.%s' % model, method, (args, kwargs, {}))
def system(self, method):
return self.call('system', method, params=[])
the key point is the call that must be done with the context in order to be executed in the right way !!
def model(self, model, method, args=[], kwargs={}):
return self.call('model.%s' % model, method, (args, kwargs, {}))
hope it helps
regards
I am trying to mock a get request with requests_mock, but it doesn't seem to get it right.
My function calling a third-party API defined in a file lookup.py:
from botocore.vendored import requests
def get_data():
url = 'https://abc.something.com/datapackage'
url_params={
'v': 2,
'auth_apikey':'xyz'
}
resp = requests.get(url, params=url_params)
return resp.json()
I am using py.test to run my tests and in my test file. I have a fixture:
import requests_mock
import requests, pytest
from lookup import get_data
#pytest.fixture
def req_mock(request):
m = requests_mock.Mocker()
m.start()
request.addfinalizer(m.stop)
return m
def test_api_gets_data(req_mock):
sample={
'key1':123
}
lookup_url = 'https://abc.something.com/datapackage'
query_params = {
'v': 2,
'auth_apikey':'xyz'
}
req_mock.get(lookup_url, json=sample)
resp = get_data()
Apparently, requests_mock isn't able to use the same session as the requests in the get function, so it isn't getting mocked.
Is there a better way to do this?
I'm using Python 3.6, requests 2.18, requests-mock 1.52 and pytest 3.0.7.
at lookup.py files, lookup_url will raise NameError cause name lookup_url not defined.
use url and don't forget to change params=url_params, so the code will be something like this:
resp = requests.get(url, params=url_params)
Apparently you can't mock from botocore.vendored import requests with requests_mock.
Instead use unittest.mock to mock the response.
from unittest import mock
class MockResponse:
def __init__(self, status_code, json_data=None):
self.json_data = json_data
self.status_code = status_code
def json(self):
return self.json_data
def raise_for_status(self):
if self.status_code >= 500:
raise Exception
item_not_found = {
"Response": {
"StatusCode": "ItemNotFound",
}
}
item_not_found_resp = MockResponse(200, item_not_found)
#mock.patch('botocore.vendored.requests.get', return_value=item_not_found_resp)
def test_api_returns_not_found_when_third_party_api_returns_item_not_found(mc):
resp = get(e1, c)
exp_resp = {
"statusCode": 404,
"body": json.dumps({
'error': 'no item found'
})
}
request_url = mc.call_args[0][0]
request_params = mc.call_args[1]['params']
assert lookup_url == request_url
assert query_params == request_params
assert exp_resp == resp
I've got a cherrypy app and I'm trying to change response header Content-type. I'm trying to do that with cherrypy.response.header['Content-Type'] = 'text/plain'. Unfortunately I'm still getting 'text/html'. I want to have set one content type for ok request and another content type for error message. The only way how can I change content type is with my decorator. But this set type for the method and I need to change it. Do you know where could be a problem?
My config:
config = {
'/': {
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
'tools.response_headers.on': True,
'tools.response_headers.headers': [('Content-Type', 'text/html')],
}
}
def GET(self, id):
cherrypy.response.headers['Content-Type'] = 'application/x-download'
somecode
if res < None:
cherrypy.response.headers['Content-Type'] = 'text/plain'
cherrypy.response.status=404
GET._cp_config = {'response.stream': True}
def stream():
def decorate(func):
def wrapper(*args, **kwargs):
name = time.strftime("%Y%m%d-%H%M%S")
cherrypy.response.headers['Content-Type'] = 'application/x-download'
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="' + name + '.txt"'
cherrypy.response.headers['Transfer-Encoding'] = 'chunked'
return func(*args, **kwargs)
return wrapper
return decorate
#cherrypy.expose
class Network:
#stream()
def GET(self, id):
source = my_generator()
for i in source:
if res < None:
cherrypy.response.headers['Content-Type'] = 'text/plain'
cherrypy.response.status=404
break
yield bytes(i)
GET._cp_config = {'response.stream': True}
Ok, there is more complex code, config of cherrypy is in the previous comment. I have a generator, which yields me some data and this is streaming that data in file to the client. I know, there are definitely better solutions. Imagine that in res variable there is result from saving to db. The problem is, that this completely ignores my settings in the if condition. It's still returning a file (empty one). The decorator is the only way how to set content type, that's why it's there
Im trying to write a REST Client for a closed API. I call a specific function twice but it only works the first time. It's the same command. If i run the script twice with batch It works. Im suspecting Requests keeps the connection alive or caches data. How do i "reset" Requests ?
base_headers = {"Connection":"keep-alive",
"User-Agent":user_agent,
"Accept-Encoding":"gzip",
"Host":"xxxxxxxxxxx",
"Content-Type":"application/json; charset=UTF-8"}
global auth
auth = 'xxxxxx'
def create_header(doAuth = True):
headers = base_headers
if doAuth:
headers['Authorization'] = auth
return headers
def do_get(url):
return requests.get(url, headers=create_header());
def do_put(url, payload):
if payload is None:
return requests.put(url, headers=create_header())
return requests.put(url, data=payload, headers=create_header())
def upvote(postid):
return do_put("xxxxxxxxxxxxx" % postid, None).content
def set_pos(longtitude, latitude, place, country="DE"):
payload = {'xxxxx':'xxxx'}
json_payload = json.dumps(payload)
return do_put("xxxxxxxxxxxxxxx",json_payload).content
def do_post(url, payload, doAuth=True):
return requests.post(url, data=payload, headers=create_header(doAuth=doAuth))
def new_acc(place, latitude, longtitude):
access = get_access_token(place, latitude, longtitude)
print access
global auth
auth = "Bearer %s" % access['access_token']
set_pos(longtitude, latitude, place) # Does a POST
for i in range(1,30):
posts = new_acc(uni['city'], uni['latitude'], uni['longtitude'])
upvote('xxxxxxxxxxxxx')
Basically the first upvote() goes through every time but every succeding does not.
I'm almost positive that keep-alive is not doing this. I would suggest writing some handlers to debug the response if you don't get the expected response code after the request.
Also, might I suggest a slightly different design that avoids global?
class RESTClient(object):
BASE_HEADERS = {"Connection":"keep-alive",
"Accept-Encoding":"gzip",
"Host":"xxxxxxxxxxx",
"Content-Type":"application/json; charset=UTF-8"}
def __init__(self, user_agent, auth = None):
self.headers = dict(self.BASE_HEADERS)
self.headers['User-Agent'] = user_agent
self.auth = auth
def create_header(self):
headers = dict(self.headers)
if auth:
headers['Authorization'] = auth
return headers
def do_get(self, url):
return requests.get(url, headers=self.create_header());
def do_put(self, url, payload = None):
if not payload:
return requests.put(url, headers=self.create_header())
return requests.put(url, data=payload, headers=self.create_header())
def upvote(self, postid):
return do_put("xxxxxxxxxxxxx" % postid).content
def set_pos(self, longtitude, latitude, place, country="DE"):
payload = {'xxxxx':'xxxx'}
json_payload = json.dumps(payload)
return do_put("xxxxxxxxxxxxxxx",json_payload).content
def do_post(self, url, payload, do_auth = None):
return requests.post(url, data=payload, headers=self.create_header())
def new_acc(self, place, latitude, longtitude):
access = get_access_token(place, latitude, longtitude)
print access
self.auth = "Bearer %s" % access['access_token']
set_pos(longtitude, latitude, place)
rc = RESTClient('Mozilla/5.0 ... Firefox/38.0', 'my-auth-token')
rc.upvote(post_id)
etc...
It could be that your use of globals is breaking things. Having not run your code, I can't check, but I would avoid using globals and favor tighter control of your state via objects.
EDIT:
Given that this answer was accepted by the OP, I am assuming the defect was caused by mutation of globals.