Attempting to use GCP Authorized Session get method in Python to query data in GCP. The doc shows:
get(url, **kwargs)
Sends a GET request. Returns Response object.
Parameters:
url – URL for the new Request object.
**kwargs – Optional arguments that request takes.
Return type:
requests.Response
I set up a kwarg dict as kwargs = {'page_size': 2000'}
However, when I passed it to the call authsess.get('someurl', kwargs), I get the following error...
TypeError: get() takes 2 positional arguments but 3 were given.
It works fine using just the url, but, I will need to add parms (specifically a nextPageToken as if one is returned)
Can someone please give me a little guidance on what I am missing here? Do I need to encode the url and parms together? or? I have tried various options here, but, just can't get it to work and not sure yet just 'how' to interpret/implement what I find in the doc for making http requests...
Thanks in advance.
OK, sorry if I wasted anyone's time. The answer is that I needed to add 'params=' to the beginning of the parameters string... i.e., authsess.get('someurl', params=kwargs)
Really wish that had been mentioned in the doc....
Related
I'm using Python with the Django Rest framework and am trying to receive webhook events correctly from stripe.
However I constantly get this error:
stripe.error.SignatureVerificationError: No signatures found matching the expected signature for payload
This is the code:
WEBHOOK_SECRET = settings.STRIPE_WEBHOOK_SK
#csrf_exempt
def webhook(request):
sig_header = request.headers.get('Stripe-Signature', None)
payload = request.body
try:
event = stripe.Webhook.construct_event(
payload=payload,
sig_header=sig_header,
secret=WEBHOOK_SECRET
)
except ValueError as e:
raise e
except stripe.error.SignatureVerificationError as e:
raise e
return HttpResponse(status=200)
I have also tried modifying the request body format like so:
payload = request.body.decode('utf-8')
# and also
payload = json.loads(request.body)
And yet no luck.
The error is coming from the verify_header() class method inside the WebhookSignature class.
This is the part of the method where it fails:
if not any(util.secure_compare(expected_sig, s) for s in signatures):
raise error.SignatureVerificationError(
"No signatures found matching the expected signature for payload",
header,
payload,
)
So I printed out exptected_sig and signatures before this line and found that regardless of what format request.body is in, signatures is always there (which is good), but they never match the signature from the header.
Why is this?
When Stripe calculates the signature for the Event it sends you, it uses a specific "payload" representing the entire Event's content. The signature is done on that exact payload and any change to it such as adding a new line, removing a space or changing the order of the properties will change the payload and the corresponding signature.
When you verify the signature, you need to make sure that you pass the exact raw payload that Stripe sent you, otherwise the signature you calculate won't match the Stripe one.
Frameworks can sometimes try to be helpful when receiving a request and they detect JSON and automatically parse it for you. This means that you think you are getting the "raw payload/body" but really you get an alternate version. It has the same content but it doesn't match what Stripe sent you.
This is fairly common with Express in Node.js for example. So, as the developer, you have to explicitly request the exact raw/original payload Stripe sent you. And how to do this can differ based on a variety of factors. There are 2 issues on the stripe-node github with numerous potential fixes here and here.
With Django, the same can happen and you need to make sure that your code requests the raw payload. You seem to use request.body as expected but that's one thing you want to dig into further.
Additionally, another common mistake is using the wrong Webhook secret. If you use the Stripe CLI for example, it creates a new secret for you that is different from the one you see in the Dashboard for this Webhook Endpoint. You need to make sure you use the correct secret based on the environment you're in.
Using the HTTPretty library for Python, I can create mock HTTP responses for my unit tests. When the code I am testing runs, instead of my request reaching the third party, the request is intercepted and my code receives the response I configured.
I then use last_request() and can check the url my code requested, any parameters, etc.
What I would like is to know how can I access not just the last request but also any other requests my code sent before the last one.
This seems to be possible. In the documentation it uses a list called latest_requests. For example here
But that doesn't seem to work for me. I get an AttributeError AttributeError: module 'httpretty' has no attribute 'latest_requests'
Here is some code that illustrates what I am trying to do and where I get AttributeError
import httpretty
import requests
httpretty.enable()
httpretty.register_uri(
method=httpretty.GET,
uri='http://www.firsturl.com',
status=200,
body='First Body'
)
httpretty.enable()
httpretty.register_uri(
method=httpretty.GET,
uri='http://www.secondurl.com',
status=200,
body='secondBody'
)
firstresponse = requests.get('http://www.firsturl.com')
secondresponse = requests.get('http://www.secondurl.com')
print(httpretty.latest_requests[-1].url)
# clean up
httpretty.disable()
httpretty.reset()
Thanks!!
Unfortunately, after reading the docs and attempting to get your code working, I can only describe the documentation as blatantly incorrect. There appear to be three | separate | pull requests from several years ago that claim to make httpretty.latest_requests a real attribute but none of them have merged in for whatever reason.
With all of that said, I managed to get the list of all previous requests by calling
httpretty.HTTPretty.latest_requests
This returns a list of HTTPrettyRequest objects. Seeing as httpretty.last_request() returns an HTTPrettyRequest object, that attribute is probably what you're looking for.
Unfortunately, .url is not defined on that class (but it is defined on the blank request object which doesn't make any sense). If you want to check that the request URL is what you're expecting, you pretty much have to try reconstructing it yourself:
req = httpretty.HTTPretty.latest_requests[-1]
url = req.headers.get('Host', '') + req.path
If you're passing anything in the query string, you'll have to reconstruct that from req.querystring although that's not ordered so you probably don't want to turn that into a string for matching purposes. Also, if all of your requests are going to the same domain, you can leave off the host part and just compare req.path.
I would like to use the reverse url lookup available in a django template using keyword arguments instead of positional ones.
I have it working using positional arguments just fine as such:
HTML:
download
URL:
(r'^generator/download/(?P<customer_id>\d+)/$', 'generator.views.send_file', name='download'),
View definition:
def send_file(request, customer_id):
The problem is that I am noticing a security flaw in that now anyone can simply enter as a url like:
/generate/download/<any number>/
and download a file that is meant only for someone else. I understand that this risk might be able to be mitigated by using user permissions etc, but I still would like to add another layer of security just in case. Maybe I am wrong in my thinking that a keyword argument is safer in this regard because it is not simply available to be passed in the url... But that is what I am thinking.
The code as I think it should work looks like:
HTML:
download
URL:
(r'^generator/download/$', 'generator.views.send_file', name='download'),
View definition:
def send_file(request, customer_id=None):
customer = get_object_or_404(Customer, pk=customer_id)
... other code
meaning if /generate/download/ is entered in the url (without the accompanying kwarg) it would just give them 404.
but I am getting the following error when I try to use this code:
Reverse for 'download' with arguments '()' and keyword arguments '{u'customer_id': 33}' not found. 1 pattern(s) tried: ['generator/download/$']
I'm sure it is something silly that I simply passed over in the django url dispatcher docs, or perhaps it is in the way I am defining my view (perhaps I need **kwargs as the argument?) but I can't seem to find it for the life of me.
Your help is much appreciated.
Your assumption is unfortunately completely wrong. Keyword arguments are passed in the URL, they are simply sent to the view function in a different way - in kwargs instead of args.
The simplest way to solve your problem is just to check the user in the download function itself.
def download(request, pk):
obj = Download.objects.get(pk)
if obj.customer_id != request.user.id:
return HttpResponseForbidden()
I'm trying to implement a batch request method in pyramid. I see in the docs that it's done with
subrequest = Request.blank('/relative/url')
request.invoke_subrequest(subrequest)
I'm just wondering how do you pass along the headers and cookies? Is it already done for you or is it
request.invoke_subrequest(subrequest, cookies=request.cookies, headers=request.headers)
What about parameters for different methods? The docs only have a POST keyword arg.
I feel like the docs are a little vague, or I can't find the correct docs on how to do this. Thanks
I'm just wondering how do you pass along the headers and cookies?
From http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/subrequest.html#subrequest-chapter :
The pyramid.request.Request.invoke_subrequest() API accepts two
arguments: a positional argument request that must be provided, and
use_tweens keyword argument that is optional; it defaults to False.
This tells us that the constructor only wants a Request object, and optionally a value for use_tweens, so no, this
request.invoke_subrequest(subrequest, cookies=request.cookies, headers=request.headers)
will not work.
Then, from http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/subrequest.html
It's a poor idea to use the original request object as an argument to
invoke_subrequest(). You should construct a new request instead as
demonstrated in the above example, using
pyramid.request.Request.blank(). Once you've constructed a request
object, you'll need to massage it to match the view callable you'd
like to be executed during the subrequest. This can be done by
adjusting the subrequest's URL, its headers, its request method, and
other attributes. The documentation for pyramid.request.Request
exposes the methods you should call and attributes you should set on
the request you create to massage it into something that will actually
match the view you'd like to call via a subrequest.
So basically, you need to configure your request before you pass it to invoke_subrequest().
Luckily there is an entire page that documents the Request class. There we can find a whole lot options to configure it, etc.
What about parameters for different methods? The docs only have a POST keyword arg.
Also on the Request class documentation page, there is this
method
Gets and sets the REQUEST_METHOD key in the environment.
And on http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/viewconfig.html I found
request_method This value can be a string (typically "GET", "POST",
"PUT", "DELETE", or "HEAD") representing an HTTP REQUEST_METHOD
I must agree with you that the documentation is a little vague here and there, but I assume you can use it like this
request.method = 'POST'
# Or
request.method = 'GET'
# Etc.
Summary
You'll want to do it like this
subrequest = Request.blank('/relative/url')
# Configure the subrequest object
# set headers and other options you need.
request.invoke_subrequest(subrequest)
Note
I am aware this is not a 100% complete answer with some code that you can copy paste and it'll just work (especially regarding configuring the request object), but I think this answer contains some information that, at the very least, will get you on the right track and I hope it will be of some help to you.
The following code worked for me. It copies all (headers, cookies, query string, post parameters, etc.):
def subrequest(request, path):
subreq = request.copy()
subreq.path_info = path
response = request.invoke_subrequest(subreq)
return response
Somewhat late, but based on the above two answers here is how I did this. I didn't quite like the above answer to just copy everything. Looking at the documentation of the blank() method there is a kw argument and it says
All necessary keys will be added to the environ, but the values you pass in will take precedence. If you pass in base_url then wsgi.url_scheme, HTTP_HOST, and SCRIPT_NAME will be filled in from that value.
Assuming that the view's request contains the right header information and cookies that you need for your subrequest, you can use the following code:
#view_config( ... )
def something(request):
...
kwargs = { "cookies": request.cookies,
"host" : request.host,
}
req = Request.blank("/relative/url", **kwargs)
resp = request.invoke_subrequest(req)
Other header information (e.g. accept, accept_encoding, etc.) are properties of pyramid.request objects, and can be added to the kwargs dictionary like shown in the code snippet above.
The object returned by invoke_subrequest() is a Response object documented here.
I used this library to make API requests and got the access tokens successfully.
But the documentation does not explain how _access_token and _access_token_secret should be used afterwards future. I suppose that there should be a method like:
set_access_token(_access_token, _access_token_secret)
but I could't find a method like that in this code or documentation.
Please help me to solve this problem.
I have not used this particular library or API, but a common pattern in these cases is that you pass the token as an argument to subsequent calls. Looking at the source, I can see a function called get_user_profile in __init__.py:
def get_user_profile(self, access_token, selectors=None, headers=None, **kwargs):
"""
Get a user profile. If keyword argument "id" is not supplied, this
returns the current user's profile, else it will return the profile of
the user whose id is specificed. The "selectors" keyword argument takes
a list of LinkedIn compatible field selectors.
"""
So I'd guess you just want to pass the token as the first argument (in this instance).