Cannot get node-apn to connect - node.js

I'm trying to make a connection to APNs. It simply won't connect. I get variations of:
apn Socket error occurred +609ms { [Error: socket hang up] code: 'ECONNRESET' }
and
apn Connection error occurred before TLS Handshake +0ms
This is for a Passbook pass. Not an app. I'm using Passbook certificates.
My code is:
var apns = require('apn');
var root = process.cwd();
var fs = require('fs');
var options = {
cert: root + '/certs/new/cert.pem', /* Certificate file path */
certData: null, /* String or Buffer containing certificate data, if supplied uses this instead of cert file path */
key: root + '/certs/new/key.pem', /* Key file path */
keyData: null, /* String or Buffer containing key data, as certData */
passphrase: 'secret', /* A passphrase for the Key file */
ca: null, /* String or Buffer of CA data to use for the TLS connection */
gateway: 'gateway.sandbox.push.apple.com',/* gateway address */
port: 2195, /* gateway port */
enhanced: true, /* enable enhanced format */
errorCallback: undefined, /* Callback when error occurs function(err,notification) */
cacheLength: 100 /* Number of notifications to cache for error purposes */
};
var apnsConnection = new apns.Connection(options);
var myDevice = new apns.Device('token');
var note = new apns.Notification();
note.payload = {};
note.device = myDevice;
apnsConnection.sendNotification(note);

It appears that I mixed up my certificates. I'm sure I tried swapping them earlier but obviously didn't.
cert: Your app cert.
key: Apple's WWDR

are you behind a proxy? that could be the issue (at least it is often in my case)

Try the following structure : Read the .cert and .key files manually and set them as certData and keyData property, respectivelly. Here is the core :
var key = root + '/certs/new/key.pem'
var cert = root + '/certs/new/cert.pem';
var certData = fs.readFileSync(cert, encoding='ascii');
var keyData = fs.readFileSync(key, encoding='ascii');
var apnsConnection = new apns.Connection({
certData: certData,
keyData: keyData,
gateway: 'gateway.sandbox.push.apple.com',
port: 2195,
... /* other configs of course */
});

Related

Node.js https server throws 'bad decrypt' error if cert passphrase has $ in it

Any other special char in the passphrase works but not when passphrase has $ in it for some reason, for example passphrase like te$t, the error thrown while starting the server is -
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
at Error (native)
at Object.createSecureContext (_tls_common.js:106:19)
at Server (_tls_wrap.js:598:25)
at new Server (https.js:36:14)
at Object.exports.createServer (https.js:56:10)
Here is how the code looks like -
const sslConfig = {
secureOptions: ...,
cert: fileSystem.readFileSync(<cert path>),
key: fileSystem.readFileSync(<key path>),
ciphers: [ ... ].join(':'),
};
if (<has passphrase setup>) {
sslConfig.passphrase = fileSystem.readFileSync(<passphrase path>, { encoding: 'utf8' }),
// console logging the passphrase here shows the correct passphrase
// file path for passphrase file is valid
}
const expressApp = express(); // followed by settings specific to express.js
https.createServer(sslConfig, expressApp).listen(...);
FYI - this is using Node.js v0.12.7, its a legacy app. Upgrading node version is not an option at the moment.
Any pointers?

GRPC Golang Server and NodeJS client. TLS connect failed

Everything works fine when I don't use TLS. But when I do, it does not connect. More details:
I have configured the Golang GRPC server exactly like how this blog says https://bbengfort.github.io/programmer/2017/03/03/secure-grpc.html in Mutual TLS with Certificate Authority section. The server is up and running just fine.
Now I have a client written in NodeJS, trying to send some data through grpc. I have configured the NodeJS like below:
var PROTO_PATH = __dirname + '/protos/log.proto';
var grpc = require('grpc');
var protoLoader = require('#grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
PROTO_PATH,
{keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
var ssl_creds = grpc.credentials.createSsl(fs.readFileSync('ssl/ca.crt'), fs.readFileSync('ssl/client.key'), fs.readFileSync('ssl/client.crt'));
var log_proto = grpc.loadPackageDefinition(packageDefinition).log;
var client = new log_proto.LogData('<IP>:<PORT>',ssl_creds);
I created the certificates like how it is mentioned here: https://github.com/grpc/grpc/issues/6757. Ofcourse, i did see this comment: https://github.com/grpc/grpc/issues/6757#issuecomment-264617793.
I am still seeing the error when I run NodeJS client:
{ Error: 14 UNAVAILABLE: Connect Failed
at Object.exports.createStatusError (/app/node_modules/grpc/src/common.js:91:15)
at Object.onReceiveStatus (/app/node_modules/grpc/src/client_interceptors.js:1204:28)
at InterceptingListener._callNext (/app/node_modules/grpc/src/client_interceptors.js:568:42)
at InterceptingListener.onReceiveStatus (/app/node_modules/grpc/src/client_interceptors.js:618:8)
at callback (/app/node_modules/grpc/src/client_interceptors.js:845:24)
code: 14,
metadata: Metadata { _internal_repr: {} },
details: 'Connect Failed' }
Certificate details:
SSLv3
TLSv1.2
EDIT:
I added env variable GRPC_VERBOSITY as DEBUG and found the following: Peer name <IP> is not in peer certificate
So the issue was that the certificate couldn't hold IP address as the hostname. It should have a name and not an IP - fixed it by providing a name and overriding the target name.
const options = {
'grpc.ssl_target_name_override' : 'simple-host',
'grpc.default_authority': 'simple-host'
};
var client = new log_proto.LogData('<IP>:<PORT>',ssl_creds,options);

NodeJS STARTTLS Use SNI

I'm building a simple, STARTTLS capable POP3 Proxy in Node.JS and I'm having quite a hard time.
The proxy serves as a front-end for many back-end servers, so it must load their certificates dynamically, depending on the Client's connection.
I'm trying to use the SNICallback, which brings me the servername the client uses, but I can't set the right certificate after this, because I need one certificate before I have this call, when I create the secure context.
The code is as bellow:
// Load libraries
var net = require('net');
var tls = require('tls');
var fs = require('fs');
// Load certificates (created with openssl)
var certs = [];
for (var i = 1; i <= 8; i++) {
var hostName = 'localhost' + i;
certs[hostName] = {
key : fs.readFileSync('./private-key.pem'),
cert : fs.readFileSync('./public-cert' + i + '.pem'),
}
}
var server = net.createServer(function(socket) {
socket.write('+OK localhost POP3 Proxy Ready\r\n');
socket.on('data', function(data) {
if (data == "STLS\r\n") {
socket.write("+OK begin TLS negotiation\r\n");
upgradeSocket(socket);
} else if (data == "QUIT\r\n") {
socket.write("+OK Logging out.\r\n");
socket.end();
} else {
socket.write("-ERR unknown command.\r\n");
}
});
}).listen(10110);
and upgradeSocket() is as follows:
function upgradeSocket(socket) {
// I need this 'details' or handshake will fail with a message:
// SSL routines:ssl3_get_client_hello:no shared cipher
var details = {
key : fs.readFileSync('./private-key.pem'),
cert : fs.readFileSync('./public-cert1.pem'),
}
var options = {
isServer : true,
server : server,
SNICallback : function(serverName) {
return tls.createSecureContext(certs[serverName]);
},
}
sslcontext = tls.createSecureContext(details);
pair = tls.createSecurePair(sslcontext, true, false, false, options);
pair.encrypted.pipe(socket);
socket.pipe(pair.encrypted);
pair.fd = socket.fd;
pair.on("secure", function() {
console.log("TLS connection secured");
});
}
It handshakes correctly but the certificate I use is the static one in 'details', not the one I get in the SNICallback.
To test it I'm running the server and using gnutls-cli as a Client:
~$ gnutls-cli -V -s -p 10110 --crlf --insecure -d 5 localhost3
STLS
^D (Control+D)
The above command is supposed to get me the 'localhost3' certificate but it's getting the 'localhost1' because it's defined in 'details' var;
There are just too many examples throughout the internet with HTTPS or for TLS Clients, which it's a lot different from what I have here, and even for Servers as well but they're not using SNI. Any help will be appreciated.
Thanks in advance.
The answer is quite simple using tls.TLSSocket, though there is a gotcha with the listeners.
You have to remove all the listeners from the regular net.Socket you have, instantiate a new tls.TLSSocket using your net.Socket and put the listeners back on the tls.TLSSocket.
To achieve this easily, use a wrapper like Haraka's tls_socket pluggableStream over the regular net.Socket and replace the "upgrade"
function to something like:
pluggableStream.prototype.upgrade = function(options) {
var self = this;
var socket = self;
var netSocket = self.targetsocket;
socket.clean();
var secureContext = tls.createSecureContext(options)
var tlsSocket = new tls.TLSSocket(netSocket, {
// ...
secureContext : secureContext,
SNICallback : options.SNICallback
// ...
});
self.attach(tlsSocket);
}
and your options object would have the SNICallback defined as:
var options {
// ...
SNICallback : function(serverName, callback){
callback(null, tls.createSecureContext(getCertificateFor(serverName));
// ...
}
}

Node js apple push notification with sending custom data

Now push notification works properly, but I don't know how to send custom data with push notification.
My node js library for push notification is 'apn'.
Code for push notification :
var apns = require('apn');
/* Data to be send with push notification */
var ntfnDetails = {};
ntfnDetails = data.ntfnDetails;
var options = {
cert: 'FitCert.pem', /* Certificate file path */
certData: null, /* String or Buffer containing certificate data, if supplied uses this instead of cert file path */
key: 'FITHUDLEKEY.pem', /* Key file path */
keyData: null, /* String or Buffer containing key data, as certData */
passphrase: 'titech!##', /* A passphrase for the Key file */
ca: null, /* String or Buffer of CA data to use for the TLS connection */
gateway: 'gateway.push.apple.com',/* gateway address */
port: 2195, /* gateway port */
enhanced: true, /* enable enhanced format */
errorCallback: undefined, /* Callback when error occurs function(err,notification) */
cacheLength: 100 /* Number of notifications to cache for error purposes */
};
var apnsConnection = new apns.Connection(options);
var myDevice = data.device_id;
var note = new apns.Notification();
note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
note.badge = 3;
note.alert = 'Hellooo';
note.payload = {'messageFrom': 'Caroline'};
apnsConnection.pushNotification(note, myDevice);
In this I want to send 'ntfnDetails' variable with this push notification.
Please help me to find a solution...
Thanks in advance.
I think you can set it in payload
note.payload = {'messageFrom': 'Caroline', 'ntfnDetails' : ntfnDetails };
Check this apple-push-notification-with-sending-custom-data

azure table services authentication

while writing application using nodejs/azure and table services, how can we set what type of authorization should be used.
Shared Key Lite (or) Shared Key.
How can we set that?
It depends how you're accessing Table Services. If you use the SDK you can do it like this:
Shared Key
var sharedKey = = new SharedKeyTable(storageAccount, storageAccessKey, usePathStyleUri);
var tableService = azure.createTableService(null, null, null, sharedKey);
Shared Key Lite
var sharedKeyLite = = new SharedKeyLiteTable(storageAccount, storageAccessKey, usePathStyleUri);
var tableService = azure.createTableService(null, null, null, sharedKeyLite);
Take a look at the code and you'll see that Shared Key will be used if you omit the authentication provider.
If you use http.request you need to specify the type in the authorization header:
Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"
So your code will be something like this:
var http = require('http');
function doSomethingWithTables() {
var settings = {
host: ...,
port: 80,
path: ...,
headers: {},
method: 'GET'
};
settings.headers['Authorization'] = 'SharedKeyLite myaccount:xxiofojpfzaopfiaz';
var req = http.request(settings);
req.write(...);
req.on('response', function(res){
...
});
}

Resources