I am following a tutorial that requires me to open a socket and send a payload with a certificate: http://blog.serverdensity.com/how-to-build-an-apple-push-notification-provider-server-tutorial/.
I am having a bit of difficulty in figuring out how to do the following with python:
// Open the connection
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apns-dev.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
// Send the payload
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
// Close Resources
socket_close($apns);
fclose($apns);
I've used python-requests in the past. But only for simple get requests.
Can I use python-requests to rewrite the above code in python, or is there something better suited for this task?
Looking at the PHP documentation fo stream_context_create, and the tutorial you're following I think what you're trying to accomplish is opening a SSL secured socket connection to gatway.sandbox.push.apple.com.
I think the python module you want to look at is the ssl module. There's an example of connecting to a server from a client, probably setting the keyfile and certfile options of ssl.wrap_socket() to the certificate you created and registered to talk to the apple server.
Related
iOS 11.x Swift 4.0
Yes, I know there a dozens solutions out there that will send push notifications for you, but I am looking to create a native solution.
Now I managed to put some PHP code together that works, within it I construct a APNS payload and then pack it's way off to Apple, which of course sends it to my client. It is only 10 lines of code, but now I need to convert it to Swift.
$payload='{
"aps": {
"alert":{
"title": "Yo",
"body":"Stay Cool" },
"badge":99,
"category":"new.category",
"sound": "default"
},
"misc": "tag"
}';
$apnsHost = 'gateway.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apns-dev.pem';
$deviceToken = '7effd4dfc158d922c867c1e3c99fd46296e2b1afcd080a63a2da398bce1c9bb3';
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apns-dev.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
echo $error;
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
?>
I find this answer on SO which looks like my man, but no ... there is no certificate [.pem] on this is there?
How should Secure Transport TLS be used with BSD sockets in Swift?
I am out my depth right now? Any help/pointers to the right path desperately needed?
I am following a tutorial https://blog.serverdensity.com/how-to-build-an-apple-push-notification-provider-server-tutorial/ to implement connectivity with apple APNS server. The tutorial provided a php code for this:
// Open the connection
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apns-dev.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
// Send the payload
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
// Close Resources
socket_close($apns);
fclose($apns);
I want to write this in Perl. What is the best equivalent of PHP's stream_context_create(). I tried something like the below, but didnt work.
use IO::Socket::SSL;
my $client = IO::Socket::SSL->new(
# where to connect
PeerHost => "gateway.sandbox.push.apple.com",
PeerPort => "2195",
SSL_cert_file =>'localcert.pem',
) or die "failed connect or ssl handshake: $!,$SSL_ERROR";
I have a rare situations for sending push notifications via php which I cant figure out. I have a simple php script that send the notification shown below. If I execute this file via the command line php script.php it works just fine. If I execute via web http://domain.com/script.php it give me a Permission Denied Error. I have the correct cert path, not password for the cert. Any ideas?
Warning: stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195 (Permission denied)
...............
$apns = connect_apns('gateway.push.apple.com', '2195');
$write = send_payload($apns, $deviceToken, $payload);
fclose($apns);
}
function connect_apns($apnsHost, $apnsPort) {
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', 'cert.pem');
return stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 60, STREAM_CLIENT_CONNECT, $streamContext);
}
function send_payload($handle, $deviceToken, $payload) {
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
return fwrite($handle, $apnsMessage);
}
so after much time spending looking at this I noticed that I had Selinux enabled. If you want to keep it enabled you need to set the property httpd_can_network_connect to true by issuing this command: setsebool -P httpd_can_network_connect 1. Otherwise just just disable selinux by going to vim /etc/selinux/config and set SELINUX=disabled.
I'm trying so send push notifications ton my iPhone (APNS). I read this post and try to implement it. So all my certificates are good (normaly).
Now I have this php script :
$device = '4f30e047 c8c05db9 3fa87e7d ca5325f7 738cb2c0 0b4a02d4 d4329a42 a7128173'; // My iphone deviceToken
$payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');
$payload['server'] = array('serverId' => $serverId, 'name' => $name);
$output = json_encode($payload);
$apnsCert = 'apple_push_notification_production.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $device)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
//socket_close($apns); seems to be wrong here ...
fclose($apns);
When I run this script nothing happen. no error just an empty page but my iPhone doesn't receive the push notification ...
Have you got an idea?
Thanks a lot !
no space in device token, strip them
For development certificate you need url
'ssl://gateway.sandbox.push.apple.com:2195'
but for production
'ssl://gateway.push.apple.com:2195'
Strip the spaces from token and even then it's not work then
$apnsHost = 'gateway.sandbox.push.apple.com';
Remove "sandbox" from this url and it will run.
If you have more than one device and you loop through them I found that you have to create a new stream_context_create for each fwrite to prevent apple from closing the connection for a bad token.
FYI
To send notifications success fully you have to do 1 more thing.
Replace $output = json_encode($payload);
to $payload = json_encode($payload);
You are missing to provice certificate private key. Add this row:
stream_context_set_option($streamContext, 'ssl', 'passphrase', $certificatePrivateKey);
When I try to send Push Notifications I get this error: "Connection refused", but I don't know why... I've uploaded my apns-dev.pem in the same directory as well in the root-directory but that won't work either.
<?php
$payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apns-dev.pem';
$apnsPass = 'secret';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
stream_context_set_option($streamContext, 'ssl', 'passphrase', $apnsPass);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 60, STREAM_CLIENT_CONNECT, $streamContext);
if (!$apns) {
echo "Error: $errorString ($error)";
}
// Do this for each
$deviceToken = '00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000';
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
// End do
socket_close($apns);
fclose($apns);
?>
Does anyone know what I'm doing wrong? When I remove the passphrase and don't send it it doesn't work either...
Make sure the outgoing port 2195 is open.This would be in your firewall config.
You don't want a passphrase unless your .pem file requires one. The connection requires peer verification (option verify_peer) turned on. Also, make sure $apnsCert is the valid path to the certificate, you can use an absolute path as a sanity check.
Lastly, this shouldn't effect your ability to connect, but your device token needs to be valid.
I've know fixed that error by adding this: STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT
Know I'm not getting any errors, but I don't receive any notification. I think the Dev-token is not valid know, so, this is how it look like
numbers numbers numbers numbers numbers numbers numbers numbers.
The spaces are removed in this line:
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
Edit: I founded the problem:
My server is refusing the outgoing port, just sent a mail, hoping they can activate it...