Closed freeridre closed 10 months ago
we're actively using push notifies and it's working.
reqs for us:
django-walletpass>=3.0
w/ Dj4.2 and py 3.11
It's good to know. In that case the issue is with my inplementation. Do you have any idea?
nope. but I would myself debug like this:
In order to work the push_notifiaction firstly, my pass should be registered. Am I right? Are there any ways to debug why my pass is not registered?
use the signal for pass registration to assert that you get the proper response from apple upon registration
As far as I have recently understood, apple does not take a part of the pass registration process. Apple only takes part after the pass registered to your db.
either one: if the device or apple themselves notifies you: the webhook is called and the Django signal fired.
My django webapp is connected with apache2 where I can monitor the in-out coming requests, but I have never saw any request from apple wallet, after the pas added to the wallet. Then my webservice url could be inappropriate?!
Do you use the master branch?
My django webapp is connected with apache2 where I can monitor the in-out coming requests, but I have never saw any request from apple wallet, after the pas added to the wallet. Then my webservice url could be inappropriate?!
get a passbook file, unzip it, see the json data and validate the callback url is valid
Do you use the master branch?
⬆️
My django webapp is connected with apache2 where I can monitor the in-out coming requests, but I have never saw any request from apple wallet, after the pas added to the wallet. Then my webservice url could be inappropriate?!
get a passbook file, unzip it, see the json data and validate the callback url is valid
hmm very strange. If I try to open the "callback url" alias WebserviceUrl, then I get
your connection is not private NET::ERR_CERT_COMMON_NAME_INVALID
error, and if I proceed, then I get
Page not found 404 error
for www.senitysecuritysystems.com/passes
then it must have https and you need to check the url setup according to docs (RTFM).
Can you request www.example.com/passes in your webapp or in other words what happends if you request your website? I mean does it work for you? One of my colleague checked this www.senitysecuritysystems.com/passes and it's in https, and he got page not found 404 error.
hey, will not access unknown urls and do your debugging. sending proper HTTP requests and inspecting the logs should be sufficient. in any other case write proper tests to learn what your code does.
I realized that the communication happends, but it breaks with the ssl handshake process, so now I try to recreate the https certificate.
I recreated the certificate now the communication works, and I see the requests when the Apple wallet tries to register the pass, but unfortunatelly I get this error every time: [Wed Jan 10 15:26:27.296571 2024] [wsgi:error] [pid 10109] [remote 37.76.10.117:16848] Unauthorized: /api/passes/v1/devices/58149c6696c2592240aa7ab4510cc4b7/registrations/pass.com.senity.application/Cu64anbaTCm-gyMzDbUp9SpNs_g
using search feature of Gh reveals: https://github.com/search?q=repo%3ADevelatio%2Fdjango-walletpass%20Unauthorized&type=code - debug the http headers, if that code is not hit, the error is not related to this lib
I still have not figured out what could be the problem. I still get these errors after the wallet tries to register the pass to push notification.
Unauthorized: /api/passes/v1/devices/b752fb2de40a42b0308e605cbaa33b23/registrations/pass.com.senity.application/1fU-M8l0U-QN4YYGNZ--5D4icQ_XzMNk
[2024-01-11 01:27:21 +0100] Register task (for device b752fb2de40a42b0308e605cbaa33b23, pass type pass.com.senity.application, serial number 1fU-M8l0U-QN4YYGNZ--5D4icQ_XzMNk; with web service url https://senitysecuritysystems.com/api/passes/) encountered error: Authentication failure
Unfortunatelly, I'm still struggling in order to register the pass for push notification. I tried the "registration" link with the postman, and I also got unauthorized error.
(0.001) SELECT
django_walletpass_pass
.id
,django_walletpass_pass
.pass_type_identifier
,django_walletpass_pass
.serial_number
,django_walletpass_pass
.authentication_token
,django_walletpass_pass
.data
,django_walletpass_pass
.updated_at
FROMdjango_walletpass_pass
WHERE (django_walletpass_pass
.pass_type_identifier
= 'pass.com.senity.application' ANDdjango_walletpass_pass
.serial_number
= 'Zcb7G_ZInUdjQDjfFVA4CbSupdBGTu1Q') LIMIT 21; args=('pass.com.senity.application', 'Zcb7G_ZInUdjQDjfFVA4CbSupdBGTu1Q') (0.001) SELECTdjango_walletpass_pass
.id
,django_walletpass_pass
.pass_type_identifier
,django_walletpass_pass
.serial_number
,django_walletpass_pass
.authentication_token
,django_walletpass_pass
.data
,django_walletpass_pass
.updated_at
FROMdjango_walletpass_pass
WHERE (django_walletpass_pass
.pass_type_identifier
= 'pass.com.senity.application' ANDdjango_walletpass_pass
.serial_number
= 'VESRSi1L7FceW4fL-ZDL277f7LuOI6lu') LIMIT 21; args=('pass.com.senity.application', 'VESRSi1L7FceW4fL-ZDL277f7LuOI6lu') Unauthorized: /api/passes/v1/devices/8037daf4905f21a1d91c17f7933ffdf9/registrations/pass.com.senity.application/VESRSi1L7FceW4fL-ZDL277f7LuOI6lu Exception while resolving variable 'name' in template 'unknown'. Traceback (most recent call last): File "/home/pi/WebService/passwebservice/.venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 47, in inner response = get_response(request) File "/home/pi/WebService/passwebservice/.venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 167, in _get_response callback, callback_args, callback_kwargs = self.resolve_request(request) File "/home/pi/WebService/passwebservice/.venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 290, in resolve_request resolver_match = resolver.resolve(request.path_info) File "/home/pi/WebService/passwebservice/.venv/lib/python3.7/site-packages/django/urls/resolvers.py", line 589, in resolve raise Resolver404({'tried': tried, 'path': new_path}) django.urls.exceptions.Resolver404: {'tried': [[<URLResolver <module 'django_walletpass.urls' from '/home/pi/WebService/passwebservice/.venv/lib/python3.7/site-packages/django_walletpass/urls.py'> (None:None) '^api/passes/'>], [<URLResolver(admin:admin) 'admin/'>], [<URLPattern '' [name='login']>], [<URLResolver <module 'UserHandler.urls' from '/home/pi/WebService/passwebservice/UserHandler/urls.py'> (None:None) 'UserHandler/'>]], 'path': 'passes/v1/devices/533e84c95651067bb2dddc4b70930696/registrations/pass.com.senity.application/_UmVM4AFHcVZ8XpSRZmVyOGWqwBxkCIE'}
please always provide full test setup info. what was your postman request alike. what headers did you send?
In the postman I tried this url with Bearer Token with this authkey: 901b71313d06d9ced98efae02e4a53b0c7fd3c6cccd23328421925c1d30eab7a0b7068f3
https://senitysecuritysystems.com/api/passes/v1/devices/511e5d2bf98ee2515d2faaa3a7f7de89/registrations/pass.com.senity.application/kwau0WmDxncH1dxtwLEX1VNaVPvpzVBx
Unfortunatelly, I got 401, unatuhorized. The problem is that I do not know what kind of authorization should I use. I chose the Bearer Token, because I found that it only needs the Token, however JWT Bearer needs more information that I do not know. Even I do not really know which authorization method should I choose from postman...
The webserver
is Apache2 under Raspbian OS with mod_wsgi
The webapp
is Django 3.2.16
The walletpas
s is django-walletpass 3.0
My https
created with certbot let's encrypt.
my settings.py:
APPLE_CER_PEM=os.environ.get("APPLE_CER_PEM")
APPLE_KEY_PEM=os.environ.get("APPLE_KEY_PEM")
APPLE_CERT_PASS=os.environ.get("APPLE_CERT_PASS")
APPLE_CERT_PASS_BYTES = APPLE_CERT_PASS.encode() if APPLE_CERT_PASS else None
APPLE_PASS_TYPE_IDENTIFIER=os.environ.get("APPLE_PASS_TYPE_IDENTIFIER")
APPLE_TEAM_ID=os.environ.get("APPLE_TEAM_ID")
APPLE_WWDR_PEM=os.environ.get("APPLE_WWDR_PEM")
APPLE_LOGO=os.environ.get("APPLE_LOGO")
APPLE_ICON=os.environ.get("APPLE_ICON")
APPLE_ICON_X2=os.environ.get("APPLE_ICON_X2")
APPLE_ICON_X3=os.environ.get("APPLE_ICON_X3")
APPLE_NFC_PUB_KEY=os.environ.get("APPLE_NFC_PUB_KEY")
APPLE_TOKEN_KEY_ID=os.environ.get("APPLE_TOKEN_KEY_ID")
APPLE_TOKEN_AUTH_KEY_FILE=os.environ.get("APPLE_TOKEN_AUTH_KEY_FILE")
APPLE_PASS_JSON_PATH=os.environ.get("APPLE_PASS_JSON_PATH")
WALLETPASS = {
'CERT_PATH': APPLE_CER_PEM,
'KEY_PATH': APPLE_KEY_PEM,
'KEY_PASSWORD': APPLE_CERT_PASS_BYTES,
'PASS_TYPE_ID': APPLE_PASS_TYPE_IDENTIFIER,
'TEAM_ID': APPLE_TEAM_ID,
'SERVICE_URL': 'https://senitysecuritysystems.com/passes/',
'PUSH_AUTH_STRATEGY': 'token',
'TOKEN_AUTH_KEY_PATH': APPLE_TOKEN_AUTH_KEY_FILE,
'TOKEN_AUTH_KEY_ID': APPLE_TOKEN_KEY_ID,
"APPLE_WWDRCA_PEM_PATH": APPLE_WWDR_PEM,
'STORAGE_CLASS': 'django.core.files.storage.FileSystemStorage',
'UPLOAD_TO': 'passes',
"STORAGE_HTTP_REDIRECT": True,
'PUSH_SANDBOX': False
}
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': '/home/pi/WebService/passwebservice/SenityProject/debug.log',
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
'__main__': { # Allows to log from the main module (your views, models, etc.)
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
},
}
my .env file:
export APPLE_CER_PEM="/home/pi/WebService/passwebservice/certificates/certificate.pem"
export APPLE_KEY_PEM="/home/pi/WebService/passwebservice/certificates/private.pem"
export APPLE_CERT_PASS=46137928
export APPLE_PASS_TYPE_IDENTIFIER="pass.com.senity.application"
export APPLE_TEAM_ID="AC825JF3W2"
export APPLE_WWDR_PEM="/home/pi/WebService/passwebservice/certificates/APPLEWWDRCAG4.pem"
export APPLE_LOGO="/home/pi/WebService/passwebservice/static/images/passes/apple/logo.png"
export APPLE_ICON="/home/pi/WebService/passwebservice/static/images/passes/apple/icon.png"
export APPLE_ICON_X2="/home/pi/WebService/passwebservice/static/images/passes/apple/icon@2x.png"
export APPLE_ICON_X3="/home/pi/WebService/passwebservice/static/images/passes/apple/icon@3x.png"
export APPLE_NFC_PUB_KEY="/home/pi/WebService/passwebservice/nfckeys/NFCPublicKey.pem"
export APPLE_TOKEN_KEY_ID="4884QQP5Y7"
export APPLE_TOKEN_AUTH_KEY_FILE="/home/pi/WebService/passwebservice/certificates/ApplePushNotificationCertificates/token/AuthKey_4884QQP5Y7.p8"
export APPLE_PASS_JSON_PATH="/home/pi/WebService/passwebservice/static/applepass"
my urls.py:
from django.contrib import admin from django.urls import path, include from django.conf.urls import url, include from UserHandler.views import ( login_user ) urlpatterns = [ url(r'^api/passes/', include('django_walletpass.urls')), path('admin/', admin.site.urls), path("", login_user, name="login"), path("UserHandler/", include("UserHandler.urls")), ]
my views.py for pass building and registering for push notifications:
@login_required(login_url='login') def dashboard_user(request): if request.method == "POST": builder = PassBuilder(directory = settings.APPLE_PASS_JSON_PATH) builder.pass_data_required["serialNumber"] = secrets.token_urlsafe(24) builder.pass_data_required["authenticationToken"] = crypto.gen_random_token() #secrets.token_hex(36) builder.pass_data_required["webServiceURL"] = "https://senitysecuritysystems.com/api/passes/" builder.pass_data["nfc"]["message"] = secrets.token_hex(4) builder.pass_data["generic"]["backFields"][0]["value"] = builder.pass_data_required["webServiceURL"] builder.pass_data["generic"]["backFields"][1]["value"] = builder.pass_data_required["serialNumber"] builder.pass_data["generic"]["backFields"][2]["value"] = builder.pass_data_required["authenticationToken"] pkpass_content = builder.build()
pass_instance = builder.write_to_model()
pass_instance.save()
#pkpass_file = open('senity.pkpass', 'rb')
#pkpass_file.write(pkpass_content)
#pass_instance = builder.write_to_model()
#pass_instance.save()
response = HttpResponse(pkpass_content, content_type="application/vnd.apple.pkpass")
response['Content-Disposition'] = 'attachment; filename="senity.pkpass"'
return response
return render(request, "dashboard.html", {})
Well, finally I solved all of the errors... 👯 What was the problem for the unauthorized error? My apache2 virtualhost configuration was not properly configured. Everytime the Apple Wallet sent request in order to register the pass for push notification, the Authorization header was empty. Why? Because my Virtual Host configuration didn't contain this: WSGIPassAuthorization On As you have already found out I use django with Apache2 therefore I have to use wsgi_mod in order to handle the django webapp with my webserver. After that some other errors appeared like: the apache2 server was not able to get the pkpass file from media/passes , because that was also missed from my Virtual Host Configuration. How could I find out what was the problem? I created the logging config for my django app, and for walletpass also, and check it with apache2 error.log file. Please, confirm that the django_walletpass_log table is only for error loggings. Only one question remained. How can I send push notification for my pass? Other thing, I noticed that the documentation doesn't properly describe the settings. The webserviceurl should https://example.com/api/passes/ not https://example.com/passes/ . I will create a PR for that.
I have already figured out how to send push notifications for the pass. I will update the documentation of this library.
Hello! Can somebody proof that the push notification works? I tried it many times, but my passes never saved into the django_walletpass_registration table. It saved only in the django_walletpass_pass table, but as far as I understood when we add the pass to the wallet, then the wallet app tries to reach the api-endpoint, and then the pass will be inside the django_walletpass_registration table, but it never happened with me.
This is my views.py: I tried it with https://senitysecuritysystems.com/passes/ and https://senitysecuritysystems.com/api/passes/ and https://senitysecuritysystems.com/api/passes/v1/ but nothing happened.
This is my settings.py:
So the passes are saved, but not registered for push notifications.