I am trying to verify that the URLs work for DJ Stripe with the Stripe CLI. Originally I was going to implement the view on my own but then I decided to go with DJ Stripe. In my original view the CLI works just file listening on my URL and running stripe trigger checkout.session.completed:
✗ stripe listen --forward-to localhost:80/webhook/subscriptions
/
⡿ Checking for new versions... A newer version of the Stripe CLI is available, please update to: v1.7.4
⢿ Getting ready... > Ready! Your webhook signing secret is whsec_flxws0UD9fzx16CMB5krTZdzy5LI63SE (^C to quit)
2021-10-11 14:29:56 --> payment_intent.created [evt_3JjUC8KxszORsacj0V7a7Kll]
2021-10-11 14:29:56 <-- [200] POST http://localhost:80/webhook/subscriptions/ [evt_3JjUC8KxszORsacj0V7a7Kll]
2021-10-11 14:29:59 --> customer.created [evt_1JjUCBKxszORsacjAxsANDCu]
2021-10-11 14:29:59 <-- [200] POST http://localhost:80/webhook/subscriptions/ [evt_1JjUCBKxszORsacjAxsANDCu]
2021-10-11 14:29:59 --> payment_intent.succeeded [evt_3JjUC8KxszORsacj0ZPYDcwj]
2021-10-11 14:29:59 <-- [200] POST http://localhost:80/webhook/subscriptions/ [evt_3JjUC8KxszORsacj0ZPYDcwj]
2021-10-11 14:29:59 --> charge.succeeded [evt_3JjUC8KxszORsacj001d3jMs]
2021-10-11 14:30:00 --> checkout.session.completed [evt_1JjUCBKxszORsacjedLR1580]
2021-10-11 14:30:00 <-- [200] POST http://localhost:80/webhook/subscriptions/ [evt_3JjUC8KxszORsacj001d3jMs]
2021-10-11 14:30:00 <-- [200] POST http://localhost:80/webhook/subscriptions/ [evt_1JjUCBKxszORsacjedLR1580]
My working non-dj-stripe code is as follows:
#csrf_exempt
def stripe_subscription_webhook_received(request):
stripe.api_key = cmu.get_stripe_api_key()
webhook_secret = request.headers['STRIPE_SIGNATURE']
payload = json.loads(request.body)
try:
event = stripe.Event.construct_from(payload, stripe.api_key)
except ValueError as e:
return HttpResponse(status=400)
if event.type == 'checkout.session.completed':
payment_intent = event.data.object
print(payment_intent)
elif event.type == 'invoice.paid':
# bunch of events...
# ...
else:
print(f"Unhandled Stripe event type: {event.type}")
cmu.email_self_about_stripe_webhook(event)
return HttpResponse(status=200)
However, when trying to utilize the DJ Stripe URL I am getting 400 errors:
✗ stripe listen --forward-to localhost:80/stripe/my_product_webhook/
⡿ Checking for new versions... A newer version of the Stripe CLI is available, please update to: v1.7.4
⣻ Getting ready... > Ready! Your webhook signing secret is whsec_flxws0UD9fzx16CMB5krTZdzy5LI63SE (^C to quit)
2021-10-11 14:37:16 --> payment_intent.created [evt_3JjUJDKxszORsacj1newBYzm]
2021-10-11 14:37:16 <-- [400] POST http://localhost:80/stripe/my_product_webhook/ [evt_3JjUJDKxszORsacj1newBYzm]
2021-10-11 14:37:21 --> customer.created [evt_1JjUJIKxszORsacjp6CsOLt1]
2021-10-11 14:37:21 <-- [400] POST http://localhost:80/stripe/my_product_webhook/ [evt_1JjUJIKxszORsacjp6CsOLt1]
2021-10-11 14:37:21 --> payment_intent.succeeded [evt_3JjUJDKxszORsacj1swQx4Mu]
2021-10-11 14:37:21 --> charge.succeeded [evt_3JjUJDKxszORsacj13CHPHjY]
2021-10-11 14:37:21 <-- [400] POST http://localhost:80/stripe/my_product_webhook/ [evt_3JjUJDKxszORsacj1swQx4Mu]
2021-10-11 14:37:21 <-- [400] POST http://localhost:80/stripe/my_product_webhook/ [evt_3JjUJDKxszORsacj13CHPHjY]
2021-10-11 14:37:21 --> checkout.session.completed [evt_1JjUJJKxszORsacjrFkPSeX2]
2021-10-11 14:37:21 <-- [400] POST http://localhost:80/stripe/my_product_webhook/ [evt_1JjUJJKxszORsacjrFkPSeX2]
Looking at the dj-stripe views.py source code it looks like this might be by design to return 400 errors given the return HttpResponseBadRequest().
#method_decorator(csrf_exempt, name="dispatch")
class ProcessWebhookView(View):
"""
A Stripe Webhook handler view.
This will create a WebhookEventTrigger instance, verify it,
then attempt to process it.
If the webhook cannot be verified, returns HTTP 400.
If an exception happens during processing, returns HTTP 500.
"""
def post(self, request):
if "HTTP_STRIPE_SIGNATURE" not in request.META:
# Do not even attempt to process/store the event if there is
# no signature in the headers so we avoid overfilling the db.
return HttpResponseBadRequest()
trigger = WebhookEventTrigger.from_request(request)
if trigger.is_test_event:
# Since we don't do signature verification, we have to skip trigger.valid
return HttpResponse("Test webhook successfully received!")
if not trigger.valid:
# Webhook Event did not validate, return 400
return HttpResponseBadRequest()
return HttpResponse(str(trigger.id))
My goal here is to move from my own webhook implementation to using the built in webhook and triggers in dj-stripe. But before I begin this migration I'd like to verify that the webhook endpoint is indeed working. Am I missing something here on how to get the Stripe CLI to play nicely with the dj-stripe URLs? In my settings.py I have DJSTRIPE_WEBHOOK_URL = "my_product_webhook/" just to make the URL more explicit. One thing that is bothering me is that my URL when looking at the DEBUG output seems to have a space in it: stripe/ my_product_webhook/ [name='webhook'] . Seeing as I am following the dj-stripe installation docs I am not clear on why this URL would have a space in it after adding path("stripe/", include("djstripe.urls", namespace="djstripe")), to my urls.py.
Edit: Logs for 400 errors:
django_web_1 | 2021-10-11 19:37:16,880 WARNING [django.request:224] log 1 281473210016224 Bad Request: /stripe/my_product_webhook/
django_web_1 | 172.23.0.4:49160 - - [11/Oct/2021:19:37:16] "POST /stripe/my_product_webhook/" 400 -
nginx_1 | 172.23.0.1 - - [11/Oct/2021:19:37:16 +0000] "POST /stripe/my_product_webhook/ HTTP/1.1" 400 0 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)"
django_web_1 | 2021-10-11 19:37:21,199 WARNING [django.request:224] log 1 281473210016224 Bad Request: /stripe/my_product_webhook/
django_web_1 | 172.23.0.4:49162 - - [11/Oct/2021:19:37:21] "POST /stripe/my_product_webhook/" 400 -
nginx_1 | 172.23.0.1 - - [11/Oct/2021:19:37:21 +0000] "POST /stripe/my_product_webhook/ HTTP/1.1" 400 0 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)"
django_web_1 | 2021-10-11 19:37:21,344 WARNING [django.request:224] log 1 281473210016224 Bad Request: /stripe/my_product_webhook/
django_web_1 | 172.23.0.4:49164 - - [11/Oct/2021:19:37:21] "POST /stripe/my_product_webhook/" 400 -
nginx_1 | 172.23.0.1 - - [11/Oct/2021:19:37:21 +0000] "POST /stripe/my_product_webhook/ HTTP/1.1" 400 0 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)"
django_web_1 | 2021-10-11 19:37:21,458 WARNING [django.request:224] log 1 281473210016224 Bad Request: /stripe/my_product_webhook/
django_web_1 | 172.23.0.4:49170 - - [11/Oct/2021:19:37:21] "POST /stripe/my_product_webhook/" 400 -
nginx_1 | 172.23.0.1 - - [11/Oct/2021:19:37:21 +0000] "POST /stripe/my_product_webhook/ HTTP/1.1" 400 0 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)"
django_web_1 | 2021-10-11 19:37:21,629 WARNING [django.request:224] log 1 281473210016224 Bad Request: /stripe/my_product_webhook/
nginx_1 | 172.23.0.1 - - [11/Oct/2021:19:37:21 +0000] "POST /stripe/my_product_webhook/ HTTP/1.1" 400 0 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)"
django_web_1 | 172.23.0.4:49172 - - [11/Oct/2021:19:37:21] "POST /stripe/my_product_webhook/" 400 -
I think you need to make sure the signing is correct, you need to go to the dashboard > developers > webhook > choose the hosted endpoint > then on signing secret click reveal. It should start with whsec... then make sure the DJSTRIPE_WEBHOOK_SECRET is the same.
if that doesn't work you can check the event log, and it may tell you what's the cause error 400. Because before it goes to your implementation, it will check whether the webhook is valid or not. You can check on the event on one of djstripe models (forgot which one).
Related
I am using gcloud CLI to configure my region and zone:
gcloud config set compute/region us-central1
gcloud config set compute/zone us-central1-c
But each command lasts for about 15 seconds, and I get a warning:
WARNING: Property validation for compute/region was skipped
Everything works fine, but why do I have 15 seconds delay, and a warning?
With verbose argument, the output is:
DEBUG: Running [gcloud.config.set] with arguments: [--verbosity: "debug", SECTION/PROPERTY: "compute/region", VALUE: "us-central1"]
Updated property [compute/region].
DEBUG: Making request: GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/?recursive=true
DEBUG: Starting new HTTP connection (1): metadata.google.internal:80
DEBUG: http://metadata.google.internal:80 "GET /computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/?recursive=true HTTP/1.1" 200 185
DEBUG: Making request: GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/token
DEBUG: http://metadata.google.internal:80 "GET /computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/token HTTP/1.1" 200 1050
DEBUG: Making request: GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/?recursive=true
DEBUG: Starting new HTTP connection (1): metadata.google.internal:80
DEBUG: http://metadata.google.internal:80 "GET /computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/?recursive=true HTTP/1.1" 200 185
DEBUG: Making request: GET http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/token
DEBUG: http://metadata.google.internal:80 "GET /computeMetadata/v1/instance/service-accounts/GOOGLE_AACOUNT_REPLACED#cloudbuild.gserviceaccount.com/token HTTP/1.1" 200 1050
DEBUG: Starting new HTTPS connection (1): compute.googleapis.com:443
DEBUG: https://compute.googleapis.com:443 "POST /batch/compute/v1 HTTP/1.1" 200 None
DEBUG: https://compute.googleapis.com:443 "POST /batch/compute/v1 HTTP/1.1" 200 None
DEBUG: https://compute.googleapis.com:443 "POST /batch/compute/v1 HTTP/1.1" 200 None
DEBUG: https://compute.googleapis.com:443 "POST /batch/compute/v1 HTTP/1.1" 200 None
DEBUG: https://compute.googleapis.com:443 "POST /batch/compute/v1 HTTP/1.1" 200 None
WARNING: Property validation for compute/region was skipped.
To make the gcloud tool easier to use, the Google Cloud will try and validate the values provided, including “compute/region”. In this case, it has to fetch a full list of available regions from the API. If this fails, for whatever reason, then it will show this warning message.
One of the many reasons may be that the Compute Engine API is not enabled. It could also be a lack of authentication, although Cloud Build will have authentication enabled by default and you don't need any special permissions to run this command.
To find out what exactly is going wrong, you can try adding the --log-http parameter to your gcloud command line. This will display the full details of any interactions with the API, including any error message in the response.
In any case, this is simply a warning, and the config entry is still being updated. This happens even if the validation fails, e.g. the region does not exist. As I mentioned above, this is just a feature to help letting the user know if they make certain types of simple mistakes.
How can I get my GraphQL API to show more query/post data in the console? I'm running a Django app that is powered by GraphQL and served via a react frontend. With regular Django paths I would see something like this in the development server:
[04/Sep/2020 11:53:08] "GET /my_app/2020/09/01/5cc4e7cc-7.png HTTP/1.1" 200 11330
But with GraphQL all I see is this:
[04/Sep/2020 11:53:18] "POST /graphql HTTP/1.1" 200 32
[04/Sep/2020 11:53:18] "POST /graphql HTTP/1.1" 200 2993
[04/Sep/2020 11:53:29] "POST /graphql HTTP/1.1" 200 11635
Any ideas?
I highly suggest checking out Silky. It's a profiling tool that can show you
the request body - that's where you'll find the graphql
speed of the response
all the DB queries sent during your request
(if you set it up) cprofiler for the request
I'm using a Flask REST API for my application and I've noticed that when I send requests from outside my own network, it's sometimes very, very slow. Most calls get completed within 150ms, but some take 8 seconds. The database connection is to a MySQL database using DBUtils.PersistentDB
The code for the endpoint:
#app.route("/name", methods=["POST"])
#jwt_refresh_token_required
def get_name_and_company():
user = get_jwt_identity()
response_object = server_functions.get_name_and_company(user)
return response_object
The function it uses:
def get_name_and_company(user):
sql = "SELECT fysios.firstname, fysios.lastname, companies.name FROM
fysios " +\
"INNER JOIN companies ON fysios.companyID = companies.id WHERE fysios.email = %s"
cursor = flask_server.get_db().cursor()
cursor.execute(sql, user)
data = cursor.fetchall()
first_name = data[0]['firstname']
last_name = data[0]['lastname']
company = data[0]['name']
response_object = name_and_company(first_name, last_name, company)
return make_response(jsonify(response_object)), 200
Here are the timestamps on the Flask server (it is the internal dev server, but I am running it with threaded=True):
[08/Mar/2019 22:16:54] "OPTIONS /login HTTP/1.1" 200 -
[08/Mar/2019 22:16:55] "POST /login HTTP/1.1" 200 -
[08/Mar/2019 22:16:55] "OPTIONS /clients HTTP/1.1" 200 -
[08/Mar/2019 22:16:55] "OPTIONS /verifyLogin HTTP/1.1" 200 -
[08/Mar/2019 22:16:55] "POST /clients HTTP/1.1" 200 -
[08/Mar/2019 22:16:57] "POST /verifyLogin HTTP/1.1" 200 -
[08/Mar/2019 22:16:57] "OPTIONS /name HTTP/1.1" 200 -
[08/Mar/2019 22:16:58] "POST /clients HTTP/1.1" 200 -
[08/Mar/2019 22:17:05] "POST /name HTTP/1.1" 200 -
As you can see, /name takes a total of 8 seconds and I can't find out why. This call to /name is just an example, it can happen on any of the calls. Is there a way to find out where the Flask application is actually stuck on?
Deploying to AWS Beanstalk solved the problem. I don't know if the limitations of the build-in dev server is to blame, but that's what did it for me.
I've been having an issue with a HTTP 500 error. It doesn't seem to cause any real problems until a few hours after the error has been shown. After the error shows up the script begins to act abnormally, giving hangups on controlling a relay and degrading in response time.
I checked my logs both in the pi and the server side and below is what I found but I can't figure out what my issue is since it seems so random, the HTTP request typically returns a 200 status and runs fine.
On the pi:
tail applocation/errors.log
2018-03-05 06:38:33 [HTTP Error] While sending data to remote Server: HTTP Error 500: Internal Server Error
2018-03-05 09:08:50 [HTTP Error] While sending data to remote Server: HTTP Error 500: Internal Server Error
on the server:
This is where it gets weird because most of the time it returns 200 but like I said every so often it gives a 500 error.
cat /var/log/ngnix/access.log | grep 9:0
47.176.12.130 - - [05/Mar/2018:09:08:29 -0800] "POST /api/1.0/access/add/ HTTP/1.1" 200 43 "-" "Python-urllib/3.4"
47.176.12.130 - - [05/Mar/2018:09:08:50 -0800] "POST /api/1.0/access/add/ HTTP/1.1" 500 38 "-" "Python-urllib/3.4"
47.176.12.130 - - [05/Mar/2018:09:09:28 -0800] "POST /api/1.0/access/add/ HTTP/1.1" 200 43 "-" "Python-urllib/3.4"
cat /var/log/ngnix/access.log | grep 500
raspberry.pi.ip - - [05/Mar/2018:06:38:33 -0800] "POST /api/1.0/access/add/ HTTP/1.1" 500 38 "-" "Python-urllib/3.4"
raspberry.pi.ip - - [05/Mar/2018:09:08:50 -0800] "POST /api/1.0/access/add/ HTTP/1.1" 500 38 "-" "Python-urllib/3.4"
in my urls.py inside my API:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^1.0/access/add/$', views.access_add, name='access_add'),
url(r'^1.0/employees/active/$', views.employees_active, name='employees_active'),
]
in my views.py inside my API:
#csrf_exempt
def access_add(request):
context = {
'status': 'error',
'msg' : ''
}
if request.method != 'POST':
context["msg"] = "This method only supports POST"
return JsonResponse(context)
try:
content = json.loads(request.body.decode('utf-8'))
except Exception as e:
context['msg'] = "Failed to load JSON parameters."
return JsonResponse(context)
key = content.get('key')
gate = content.get('gate')
code = content.get('code')
if key != KEY:
context['msg'] = "Please provide a valid API key."
return JsonResponse(context)
if gate not in ['entry','exit']:
context['msg'] = "Please provide a valid gate name."
return JsonResponse(context)
gate = 1 if gate == "entry" else 2
if not code:
context['msg'] = "Please provide an access code."
return JsonResponse(context)
context['status'] = "success"
try:
employee = Employee.objects.get(code=code)
Eventlog.objects.create(event=gate, employee=employee, status=True)
except Employee.DoesNotExist:
try:
Eventlog.objects.create(event=gate, status=False)
except:
pass
return JsonResponse(context)
I don't understand what is wrong?
callback uri:
google - http://127.0.0.1:5000/auth/google/
twitter - http://127.0.0.1:5000/auth/tw/
config:
from authomatic.providers import oauth2, oauth1
SECRET_KEY = '####'
AUTH_CONFIG = {
'google': {
'class_': oauth2.Google,
'consumer_key': '####',
'consumer_secret': ####',
'scope': ['email',],
},
'tw': {
'class_': oauth1.Twitter,
'consumer_key': '####',
'consumer_secret': '####',
},
}
controller:
from authomatic.adapters import WerkzeugAdapter
from authomatic import Authomatic
from app import app, db
from app.models.users import User
authomatic = Authomatic(
app.config.get('AUTH_CONFIG'),
app.config.get('SECRET_KEY'),
report_errors=True
)
#app.route('/auth/<provider>/', methods=['GET', 'POST'])
def auth(provider):
print "REQUEST: ", request.args
response = make_response()
result = authomatic.login(WerkzeugAdapter(request, response), provider)
if result:
if result.user:
result.user.update()
if result.user.email:
user = User.query.filter(User.email == result.user.email).first()
if user is None:
user = User(nickname=result.user.name, email=result.user.email)
db.session.add(user)
db.session.commit()
flash('A new user profile has been created for you.')
return redirect(url_for('index'))
flash('Your provider return empty data, try again later.')
return redirect(url_for('index'))
return response
and after I accept access to app in google or twitter, I have redirected to index.html page with flash massage "Your provider return empty data, try again later"
in console I see:
google:
127.0.0.1 - - [29/Nov/2014 00:41:26] "GET /login/ HTTP/1.1" 200 -
REQUEST: ImmutableMultiDict([])
127.0.0.1 - - [29/Nov/2014 00:41:27] "GET /auth/google/ HTTP/1.1" 302 -
REQUEST: ImmutableMultiDict([('state', u'bbee8547ff97e001sdss61e6'), ('code', u'4/ZJRhjCqEzAVep9UL2epaTzYI')])
127.0.0.1 - - [29/Nov/2014 00:41:30] "GET /auth/google/?state=bbee8547ff97e001d3d77161e6&code=4/ZJRhjCqEzAVep9UL2epaTzYI HTTP/1.1" 302 -
127.0.0.1 - - [29/Nov/2014 00:41:30] "GET / HTTP/1.1" 200 -
twitter:
127.0.0.1 - - [29/Nov/2014 00:43:38] "GET /login/ HTTP/1.1" 200 -
REQUEST: ImmutableMultiDict([])
127.0.0.1 - - [29/Nov/2014 00:43:42] "GET /auth/tw/ HTTP/1.1" 302 -
REQUEST: ImmutableMultiDict([('oauth_token', u'KmF9L1m5CYUY9O6joIh0'), ('oauth_verifier', u'95sGsiRz5sTxZua88G')])
127.0.0.1 - - [29/Nov/2014 00:43:44] "GET /auth/tw/?oauth_token=KmF9L1m5CYUY9O6joIh0&oauth_verifier=95sGsiRz5sTxZua88G HTTP/1.1" 302 -
127.0.0.1 - - [29/Nov/2014 00:43:44] "GET / HTTP/1.1" 200 -
May be some thing wrong if i get 302 - on response???
Please help me!
I believe this is a setup issue on the Google Developer Console.
Under the APIs & auth settings of your project you need to authorize the API's you want access to, otherwise nothing will be returned in the results var.
If you inspect it you will see an error message from Google telling you to authorize API's.
Add the following API's from here: APIs & auth > APIs, select Google+ API, this will return the result dictionary with the values you are looking for.
from authomatic.providers import openid, oauth2
CONFIG = {
'oi': {
# OpenID provider dependent on the python-openid package.
'class_': openid.OpenID,
},
'google' : {
'class_': oauth2.Google,
'consumer_key': 'GOOGLE DEVELOPER CLIENT ID',
'consumer_secret': 'GOOGLE DEVELOPER CLIENT SECRET',
'scope': ['profile', 'email']
}
}
on your index.html you will want to trigger the call like:
Sign In With Google
That should trigger the call to the google oauth login.
#app.route('/login/<provider_name>/', methods=['GET', 'POST'])
def login(provider_name):
"""
Login handler, must accept both GET and POST to be able to use OpenID.
"""
# We need response object for the WerkzeugAdapter.
response = make_response()
# Log the user in, pass it the adapter and the provider name.
result = authomatic.login(WerkzeugAdapter(request, response), provider_name)
# If there is no LoginResult object, the login procedure is still pending.
if result:
if result.user:
# We need to update the user to get more info.
result.user.update()
# The rest happens inside the template.
#result.user.data.x will return further user data
return render_template('login.html', email=result.user.email, name=result.user.name)
# Don't forget to return the response.
return response