appfeel / node-pushnotifications

Push notifications for GCM, APNS, MPNS, AMZ (automatic detection from device token)
MIT License
534 stars 126 forks source link

Send failure for TestFlight apps #67

Closed butterfly-thomasdittmar closed 6 years ago

butterfly-thomasdittmar commented 6 years ago

Hi,

I love the lib, which worked great until I tried testing in production.

Here are the steps I have done to get dev & prod certificates.

  1. Export the .cer for development =>apn_development.cer
  2. Export the .cer for production => apn_production.cer
  3. Export the .p12 for push notification push_cert.p12
  4. Convert both .cer to .pem => apn_development.pem & apn_production.pem
  5. Convert .p12 to .pem => push_cert.pem
  6. Test PN for development 6.1. Get device token from RN package react-native-push-notification 6.2. Setup NODE project and test
    const settings = {
    apn: {
        cert: './certs/aps_development.pem',
        key: './certs/push_cert.pem',
        production: false
    },
    }
    const registrationIds = []
    registrationIds.push('f43719b34e6c48d96ba6cb2055f30e673b474e103a2288d14f1045094c2e1d6d')
    const push = new PushNotifications({title:"Test", body:"This is a test PN"})
    push.send(registrationIds, customData)
    .then((results) => {
        res.send(JSON.stringify(results))
    })
    .catch((err) => {
        res.send(JSON.stringify(err))
    })

    Which works fine.

  7. Test PN for production 7.1. Put app on iTunes connect (TestFlight) 7.2. Plug-in iPhone on charger cable and open XCode -> Window -> Devices & Simulators 7.3. Install app through TestFlight and monitor logs for new device token 7.4. Use Pusher to confirm the device token and .p12 file for production. Here the log:
    Connecting to APN...  (com.<project>.production)
    Connected  (com.<project>.production)
    Pushing..
    Payload has been pushed

    7.5. Change NODE project and test

    const settings = {
    apn: {
        cert: './certs/aps_production.pem',
        key: './certs/push_cert.pem',
        production: true
    },
    }
    const registrationIds = []
    registrationIds.push('e90356be05f7296006a5d30232b30a5b4dcf580b83254ee0e27cab0328f228cd')
    const push = new PushNotifications({title:"Test", body:"This is a test PN"})
    push.send(registrationIds, customData)
    .then((results) => {
        res.send(JSON.stringify(results))
    })
    .catch((err) => {
        res.send(JSON.stringify(err))
    })

    Now I get an error [{"method":"apn","success":0,"failure":1,"message":[{"regId":"e90356be05f7296006a5d30232b30a5b4dcf580b83254ee0e27cab0328f228cd","error":{}}]}] 7.6. Try to connect with OpenSSL

    openssl s_client -connect gateway.push.apple.com:2195 -cert aps_production.pem -key push_cert.pem
    CONNECTED(00000003)
    depth=2 O = Entrust.net, OU = www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU = (c) 1999 Entrust.net Limited, CN = Entrust.net Certification Authority (2048)
    verify return:1
    depth=1 C = US, O = "Entrust, Inc.", OU = See www.entrust.net/legal-terms, OU = "(c) 2012 Entrust, Inc. - for authorized use only", CN = Entrust Certification Authority - L1K
    verify return:1
    depth=0 C = US, ST = California, L = Cupertino, O = Apple Inc., CN = gateway.push.apple.com
    verify return:1
    ---
    Certificate chain
    0 s:/C=US/ST=California/L=Cupertino/O=Apple Inc./CN=gateway.push.apple.com
    i:/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2012 Entrust, Inc. - for authorized use only/CN=Entrust Certification Authority - L1K
    1 s:/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2012 Entrust, Inc. - for authorized use only/CN=Entrust Certification Authority - L1K
    i:/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048)
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIFQTCCBCmgAwIBAgIRALUO38 ...
    -----END CERTIFICATE-----
    subject=/C=US/ST=California/L=Cupertino/O=Apple Inc./CN=gateway.push.apple.com
    issuer=/C=US/O=Entrust, Inc./OU=See www.entrust.net/legal-terms/OU=(c) 2012 Entrust, Inc. - for authorized use only/CN=Entrust Certification Authority - L1K
    ---
    Acceptable client certificate CA names
    /C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA
    /C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
    /CN=Apple Application Integration 2 Certification Authority/OU=Apple Certification Authority/O=Apple Inc./C=US
    /C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
    /C=US/ST=California/L=Cupertino/O=Apple Inc./CN=gateway.push.apple.com
    /C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Application Integration Certification Authority
    Client Certificate Types: RSA sign, ECDSA sign
    Requested Signature Algorithms: ECDSA+SHA256:0x04+0x08:RSA+SHA256:ECDSA+SHA384:0x05+0x08:RSA+SHA384:0x06+0x08:RSA+SHA512:RSA+SHA1
    Shared Requested Signature Algorithms: ECDSA+SHA256:RSA+SHA256:ECDSA+SHA384:RSA+SHA384:RSA+SHA512:RSA+SHA1
    ---
    SSL handshake has read 3617 bytes and written 2447 bytes
    ---
    New, TLSv1/SSLv3, Cipher is DES-CBC3-SHA
    Server public key is 2048 bit
    Secure Renegotiation IS supported
    Compression: NONE
    Expansion: NONE
    No ALPN negotiated
    SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : DES-CBC3-SHA
    Session-ID: 
    Session-ID-ctx: 
    Master-Key: CE0EB3415E5F3EC25AD66EDB57D148EF1F02E2740D6A4E35C5FA5DB12A2767669C7C809A5759ED05B3FFE8812D268B16
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1510283388
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
    ---

    That seemed to work. I can clearly see the certs work.

I wonder what else could be wrong?

Cheers, Tom

butterfly-thomasdittmar commented 6 years ago

UPDATE

Since there is no error output I had to find a way to print/return the error.

I went to the following file node_modules/node-pushnotifications/lib/sendAPN.js and modified the code so I get error msg's

(response.failed || []).forEach(function (failure) {
            resumed.failure += 1;
            resumed.message.push(response.failed)
            // if (failure.error) {
            //     // A transport-level error occurred (e.g. network problem)
            //     resumed.message.push({
            //         regId: failure.device,
            //         error: failure.error
            //     });
            // } else {
            //     // `failure.status` is the HTTP status code
            //     // `failure.response` is the JSON payload
            //     resumed.message.push({
            //         regId: failure.device,
            //         error: new Error(failure.response.reason || failure.response)
            //     });
            // }
        });

That produced the following return msg

[{"method":"apn","success":0,"failure":1,"message":[[{"device":"e90356be05f7296006a5d30232b30a5b4dcf580b83254ee0e27cab0328f228cd","status":"400","response":{"reason":"MissingTopic"}}]]}]

After adding topic: '<bundle identifier>' to the data I can finally send PN to production. That means that TOPIC is needed in production!!!!

alex-friedl commented 6 years ago

@butterfly-thomasdittmar yes topic is required, as can be seen in the documentation here https://github.com/appfeel/node-pushnotifications#apn Hope everything works fine now?

butterfly-thomasdittmar commented 6 years ago

Hi @alex-friedl,

Yes, everything works fine now.

As a suggestion, can you add topic: '', // REQUIRED for apn and gcm for ios into this section of the HOW-TO

alex-friedl commented 6 years ago

Good point. Made the change in https://github.com/appfeel/node-pushnotifications/pull/68