I would like to be able to send notifications through a React Native app that I built on my smartphone. This script is only supposed to send a notification to my device when the server starts up.

Config

I have a very simple node js server with this configuration:

index.js

const app = require('express')();
const http = require('http').Server(app);
const apn = require('apn');



// APNs config

const service = new apn.Provider({
    token: {
        key: 'XXXXXXXXX.p8',
        keyId: "XXXXXXXXX",
        teamId: "XXXXXXXXX",
    },
    production: process.env.NODE_ENV === 'dev' ? false : true
});

    
// express
app.get('/', (req, res) => res.send('hello world'));


// Listen to port 3000
http.listen(3000, () => console.log('run port :3000'));

Then, I add this method which allows me to send a notification to my device, where the React Native app is installed

index.js

// on server start, send a notification to my iPhone

const notif = new apn.Notification({
   title: 'Notif said:',
   alert: 'message'
})

notif.topic = 'com.name.xxxx';
notification.sound = 'ping.aiff';

service.send(notif, 'XXXXTOKENDEVICE').then(result => console.log(result))

When I run it locally with the command NODE_ENV=dev node index.js, everything goes well and I get the notification on my device.

Problem

However when I run it on a cloud host (Linode, Ubuntu 20.10) it does not work: I receive this message through the service.send() Promise:

LOG Response


{
  device: 'XXXXTOKENDEVICE',
  error: VError: endpoint error: unable to get local issuer certificate
      at Endpoint.<anonymous> (/root/app/node_modules/apn/lib/protocol/endpointManager.js:69:32)
      at Endpoint.emit (events.js:315:20)
      at Endpoint.error [as _error] (/root/app/node_modules/apn/lib/protocol/endpoint.js:149:10)
      at TLSSocket.emit (events.js:327:22)
      at emitErrorNT (internal/streams/destroy.js:92:8)
      at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
      at processTicksAndRejections (internal/process/task_queues.js:84:21) {
    jse_shortmsg: 'endpoint error',
    jse_cause: Error: unable to get local issuer certificate
        at TLSSocket.onConnectSecure (_tls_wrap.js:1501:34)
        at TLSSocket.emit (events.js:315:20)
        at TLSSocket._finishInit (_tls_wrap.js:936:8)
        at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:710:12) {
      code: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
    },
    jse_info: {}
  }
}

I tried to launch it with production mode set to true but nothing changes.

I am also a beginner with everything related to certificates etc. But once again: Everything works locally. Did I missed anything about this? Or, does my cloud server require a specific configuration?

Thank you in advance!

2

There are 2 answers

0
ozireu On

If someone who find this post has the same problem, I ended up with a solution which is to downgrade the server node version (I choose v12.16.2) and socket.io too (2.0.3).

0
Hiren Patel On

You have to include rejectUnauthorized to false in options like

var options = {
     token: {
            key: "./pushcertificates/AuthKey_XXXXXXXXXX.p8", 
            keyId: "XXXXXXXXXX",
            teamId: "XXXXXXXXXX"
     },
     production: true,
     rejectUnauthorized: false
};

This is mentioned in the documentation.

https://github.com/node-apn/node-apn/blob/master/doc/provider.markdown