From 0b11d838f53748574d58d2ce9a4e35cf580a0718 Mon Sep 17 00:00:00 2001 From: fentie Date: Sat, 21 Apr 2018 16:35:33 -0500 Subject: [PATCH 1/5] fixing typos in comments. yes, I am that kind of nerd --- website/common/script/ops/buy/buy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/common/script/ops/buy/buy.js b/website/common/script/ops/buy/buy.js index e3cb62bdca7..7b7816633bc 100644 --- a/website/common/script/ops/buy/buy.js +++ b/website/common/script/ops/buy/buy.js @@ -14,7 +14,7 @@ import errorMessage from '../../libs/errorMessage'; import {BuyGemOperation} from './buyGem'; // @TODO: remove the req option style. Dependency on express structure is an anti-pattern -// We should either have more parms or a set structure validated by a Type checker +// We should either have more params or a set structure validated by a Type checker // @TODO: when we are sure buy is the only function used, let's move the buy files to a folder @@ -23,7 +23,7 @@ module.exports = function buy (user, req = {}, analytics) { if (!key) throw new BadRequest(errorMessage('missingKeyParam')); // @TODO: Slowly remove the need for key and use type instead - // This should evenutally be the 'factory' function with vendor classes + // This should eventually be the 'factory' function with vendor classes let type = get(req, 'type'); if (!type) type = get(req, 'params.type'); if (!type) type = key; From b79961dec19d284a524e6adeb78a36dd2c3a239f Mon Sep 17 00:00:00 2001 From: fentie Date: Sat, 21 Apr 2018 16:46:47 -0500 Subject: [PATCH 2/5] replacing push-notify with node-apn in deps and in pushNotifications.js --- package.json | 2 +- website/server/libs/pushNotifications.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 78f2872b2c8..9450465c0d0 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "amazon-payments": "^0.2.6", "amplitude": "^3.5.0", "apidoc": "^0.17.5", + "apn": "^2.2.0", "autoprefixer": "^8.4.1", "aws-sdk": "^2.230.1", "axios": "^0.18.0", @@ -78,7 +79,6 @@ "postcss-easy-import": "^3.0.0", "ps-tree": "^1.0.0", "pug": "^2.0.3", - "push-notify": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9", "pusher": "^1.3.0", "rimraf": "^2.4.3", "sass-loader": "^7.0.0", diff --git a/website/server/libs/pushNotifications.js b/website/server/libs/pushNotifications.js index 52b0f557595..2c28d9dc8c0 100644 --- a/website/server/libs/pushNotifications.js +++ b/website/server/libs/pushNotifications.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import nconf from 'nconf'; // @TODO remove this lib and use directly the apn module -import pushNotify from 'push-notify'; +import { Provider, Notification } from 'apn'; import logger from './logger'; import { S3, @@ -33,7 +33,7 @@ if (APN_ENABLED) { let cert = certObj.Body.toString(); let key = keyObj.Body.toString(); - apn = pushNotify.apn({ + apn = new Provider({ key, cert, }); @@ -77,13 +77,13 @@ function sendNotification (user, details = {}) { case 'ios': if (apn) { - apn.send({ - token: pushDevice.regId, + const notification = new Notification({ alert: details.message, sound: 'default', category: details.category, payload, }); + apn.send(notification, pushDevice.regId); } break; } From 4cc690db77decdda7ff1fa146bfe1cf3bdeba5b2 Mon Sep 17 00:00:00 2001 From: fentie Date: Mon, 7 May 2018 21:52:13 -0500 Subject: [PATCH 3/5] updating calling code and tests to use node-apn --- test/api/v3/unit/libs/pushNotifications.js | 13 +++++++------ website/server/libs/pushNotifications.js | 1 - 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/api/v3/unit/libs/pushNotifications.js b/test/api/v3/unit/libs/pushNotifications.js index f033d958ff7..9dd9e64d763 100644 --- a/test/api/v3/unit/libs/pushNotifications.js +++ b/test/api/v3/unit/libs/pushNotifications.js @@ -1,6 +1,6 @@ import { model as User } from '../../../../../website/server/models/user'; import requireAgain from 'require-again'; -import pushNotify from 'push-notify'; +import apn from 'apn'; import nconf from 'nconf'; import gcmLib from 'node-gcm'; // works with FCM notifications too @@ -24,7 +24,7 @@ describe('pushNotifications', () => { sandbox.stub(gcmLib.Sender.prototype, 'send').callsFake(fcmSendSpy); - sandbox.stub(pushNotify, 'apn').returns({ + sandbox.stub(apn.Provider.prototype, 'send').returns({ on: () => null, send: apnSendSpy, }); @@ -104,10 +104,7 @@ describe('pushNotifications', () => { }, }; - sendPushNotification(user, details); - expect(apnSendSpy).to.have.been.calledOnce; - expect(apnSendSpy).to.have.been.calledWithMatch({ - token: '123', + const expectedNotification = new apn.Notification({ alert: message, sound: 'default', category: 'fun', @@ -117,6 +114,10 @@ describe('pushNotifications', () => { b: true, }, }); + + sendPushNotification(user, details); + expect(apnSendSpy).to.have.been.calledOnce; + expect(apnSendSpy).to.have.been.calledWithMatch(expectedNotification, '123'); expect(fcmSendSpy).to.not.have.been.called; }); }); diff --git a/website/server/libs/pushNotifications.js b/website/server/libs/pushNotifications.js index 2c28d9dc8c0..2fe089862da 100644 --- a/website/server/libs/pushNotifications.js +++ b/website/server/libs/pushNotifications.js @@ -1,6 +1,5 @@ import _ from 'lodash'; import nconf from 'nconf'; -// @TODO remove this lib and use directly the apn module import { Provider, Notification } from 'apn'; import logger from './logger'; import { From 041832a2df94d5b2d62283ca1d0ed4af9bff4586 Mon Sep 17 00:00:00 2001 From: fentie Date: Fri, 11 May 2018 23:20:49 -0500 Subject: [PATCH 4/5] updating APN configs to new format --- package-lock.json | 156 ++++++++++++++++----- test/api/v3/unit/libs/pushNotifications.js | 2 +- website/server/libs/pushNotifications.js | 55 ++++---- 3 files changed, 147 insertions(+), 66 deletions(-) diff --git a/package-lock.json b/package-lock.json index 04c53244a2c..88a32ea5ec3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -698,13 +698,25 @@ } }, "apn": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/apn/-/apn-1.7.8.tgz", - "integrity": "sha1-Hp2kKPtXr6lX5UIjvvc0LALCTNo=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/apn/-/apn-2.2.0.tgz", + "integrity": "sha512-YIypYzPVJA9wzNBLKZ/mq2l1IZX/2FadPvwmSv4ZeR0VH7xdNITQ6Pucgh0Uw6ZZKC+XwheaJ57DFZAhJ0FvPg==", "requires": { - "debug": "2.6.9", - "node-forge": "0.6.49", - "q": "1.5.1" + "debug": "3.1.0", + "http2": "https://github.com/node-apn/node-http2/archive/apn-2.1.4.tar.gz", + "jsonwebtoken": "8.2.1", + "node-forge": "0.7.5", + "verror": "1.10.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } } }, "append-buffer": { @@ -1790,6 +1802,11 @@ "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", "dev": true }, + "base64url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", + "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=" + }, "basic-auth": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", @@ -2674,6 +2691,11 @@ "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=" }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", @@ -5859,6 +5881,15 @@ "jsbn": "0.1.1" } }, + "ecdsa-sig-formatter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", + "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", + "requires": { + "base64url": "2.0.0", + "safe-buffer": "5.1.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -9799,6 +9830,10 @@ "sshpk": "1.14.1" } }, + "http2": { + "version": "https://github.com/node-apn/node-http2/archive/apn-2.1.4.tar.gz", + "integrity": "sha512-ad4u4I88X9AcUgxCRW3RLnbh7xHWQ1f5HbrXa7gEy2x4Xgq+rq+auGx5I+nUDE2YYuqteGIlbxrwQXkIaYTfnQ==" + }, "httpntlm": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", @@ -11039,6 +11074,30 @@ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" }, + "jsonwebtoken": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.2.1.tgz", + "integrity": "sha512-l8rUBr0fqYYwPc8/ZGrue7GiW7vWdZtZqelxo4Sd5lMvuEeCK8/wS54sEo6tJhdZ6hqfutsj6COgC0d1XdbHGw==", + "requires": { + "jws": "3.1.4", + "lodash.includes": "4.3.0", + "lodash.isboolean": "3.0.3", + "lodash.isinteger": "4.0.4", + "lodash.isnumber": "3.0.3", + "lodash.isplainobject": "4.0.6", + "lodash.isstring": "4.0.1", + "lodash.once": "4.1.1", + "ms": "2.1.1", + "xtend": "4.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -11077,6 +11136,27 @@ "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", "dev": true }, + "jwa": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", + "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", + "requires": { + "base64url": "2.0.0", + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.9", + "safe-buffer": "5.1.1" + } + }, + "jws": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz", + "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", + "requires": { + "base64url": "2.0.0", + "jwa": "1.1.5", + "safe-buffer": "5.1.1" + } + }, "kareem": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.0.7.tgz", @@ -12339,6 +12419,11 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -12349,16 +12434,36 @@ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, "lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", @@ -12385,6 +12490,11 @@ "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==" }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "lodash.rest": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/lodash.rest/-/lodash.rest-4.0.5.tgz", @@ -13509,11 +13619,6 @@ "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.4.1.tgz", "integrity": "sha512-NNY/MpBkALb9jJmjpBlIi6GRoLveLUM0pJzgbp9vY9F7IQEb/HREC/nxrixechcQwd1NevOhJnWWV8QQQRE+OA==" }, - "mpns": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mpns/-/mpns-2.1.3.tgz", - "integrity": "sha512-gPLNoVqwYoKUmNYZ2shMSdaE2XvHSRxWNzyG4DUi6Av7MSujyeOw/nj61nnQeuV/vke5E0Dni468xn0qxTHIZQ==" - }, "mquery": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.0.0.tgz", @@ -13820,9 +13925,9 @@ } }, "node-forge": { - "version": "0.6.49", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.49.tgz", - "integrity": "sha1-8e6V1ddGI5OP4Z1piqWibVTS9g8=" + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==" }, "node-gcm": { "version": "0.14.10", @@ -15513,11 +15618,6 @@ "pinkie": "2.0.4" } }, - "pipe-event": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/pipe-event/-/pipe-event-0.1.0.tgz", - "integrity": "sha1-pfXgPlqXsrdJPUsqBgzYPazLmmE=" - }, "pixelsmith": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/pixelsmith/-/pixelsmith-2.2.1.tgz", @@ -17645,19 +17745,6 @@ } } }, - "push-notify": { - "version": "git://github.com/habitrpg/push-notify.git#6bc2b5fdb1bdc9649b9ec1964d79ca50187fc8a9", - "requires": { - "apn": "1.7.8", - "bluebird": "3.5.1", - "lodash": "4.17.10", - "mpns": "2.1.3", - "node-gcm": "0.14.10", - "pipe-event": "0.1.0", - "q": "1.5.1", - "wns": "0.5.3" - } - }, "pusher": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/pusher/-/pusher-1.5.1.tgz", @@ -21716,11 +21803,6 @@ } } }, - "wns": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/wns/-/wns-0.5.3.tgz", - "integrity": "sha1-APToXPz44zg9y9gYmJBvH2rUhF8=" - }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", diff --git a/test/api/v3/unit/libs/pushNotifications.js b/test/api/v3/unit/libs/pushNotifications.js index 9dd9e64d763..8127bd9525d 100644 --- a/test/api/v3/unit/libs/pushNotifications.js +++ b/test/api/v3/unit/libs/pushNotifications.js @@ -1,6 +1,6 @@ import { model as User } from '../../../../../website/server/models/user'; import requireAgain from 'require-again'; -import apn from 'apn'; +import apn from 'apn/mock'; import nconf from 'nconf'; import gcmLib from 'node-gcm'; // works with FCM notifications too diff --git a/website/server/libs/pushNotifications.js b/website/server/libs/pushNotifications.js index 2fe089862da..9ed41200c58 100644 --- a/website/server/libs/pushNotifications.js +++ b/website/server/libs/pushNotifications.js @@ -1,6 +1,6 @@ import _ from 'lodash'; import nconf from 'nconf'; -import { Provider, Notification } from 'apn'; +import apn from 'apn'; import logger from './logger'; import { S3, @@ -11,37 +11,27 @@ const FCM_API_KEY = nconf.get('PUSH_CONFIGS:FCM_SERVER_API_KEY'); const fcmSender = FCM_API_KEY ? new gcmLib.Sender(FCM_API_KEY) : undefined; -let apn; - +let apnProvider; // Load APN certificate and key from S3 const APN_ENABLED = nconf.get('PUSH_CONFIGS:APN_ENABLED') === 'true'; const S3_BUCKET = nconf.get('S3:bucket'); if (APN_ENABLED) { - Promise.all([ - S3.getObject({ - Bucket: S3_BUCKET, - Key: 'apple_apn/cert.pem', - }).promise(), - S3.getObject({ - Bucket: S3_BUCKET, - Key: 'apple_apn/key.pem', - }).promise(), - ]) - .then(([certObj, keyObj]) => { - let cert = certObj.Body.toString(); - let key = keyObj.Body.toString(); + S3.getObject({ + Bucket: S3_BUCKET, + Key: 'apple_apn/APNsAuthKey.p8', + }).promise().then((data) => { + const key = data.Body.toString(); - apn = new Provider({ + apnProvider = APN_ENABLED ? new apn.Provider({ + token: { key, - cert, - }); - - apn.on('error', err => logger.error('APN error', err)); - apn.on('transmissionError', (errorCode, notification, device) => { - logger.error('APN transmissionError', errorCode, notification, device); - }); - }); + keyId: 'key-id', + teamId: 'developer-team-id', + }, + production: nconf.get('IS_PROD'), + }) : undefined; + }); } function sendNotification (user, details = {}) { @@ -75,14 +65,23 @@ function sendNotification (user, details = {}) { break; case 'ios': - if (apn) { - const notification = new Notification({ + if (apnProvider) { + const notification = new apn.Notification({ alert: details.message, sound: 'default', category: details.category, payload, }); - apn.send(notification, pushDevice.regId); + apnProvider.send(notification, pushDevice.regId) + .then((response) => { + response.failed.forEach((failure) => { + if (failure.error) { + logger.error('APN error', failure.error); + } else { + logger.error('APN transmissionError', failure.status, notification, failure.device); + } + }); + }); } break; } From 8d12373efe57a44c4a6a85e6d34388bd0fe92e85 Mon Sep 17 00:00:00 2001 From: fentie Date: Sat, 12 May 2018 14:35:22 -0500 Subject: [PATCH 5/5] migrating team ID and key ID to config.json --- config.json.example | 2 ++ website/server/libs/pushNotifications.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config.json.example b/config.json.example index 1073ead7cb9..0c8d2abff54 100644 --- a/config.json.example +++ b/config.json.example @@ -78,6 +78,8 @@ "PUSH_CONFIGS": { "GCM_SERVER_API_KEY": "", "APN_ENABLED": "false", + "APN_KEY_ID": "xxxxxxxxxx", + "APN_TEAM_ID": "aaabbbcccd", "FCM_SERVER_API_KEY": "" }, "SITE_HTTP_AUTH": { diff --git a/website/server/libs/pushNotifications.js b/website/server/libs/pushNotifications.js index 9ed41200c58..961cba43bb6 100644 --- a/website/server/libs/pushNotifications.js +++ b/website/server/libs/pushNotifications.js @@ -26,8 +26,8 @@ if (APN_ENABLED) { apnProvider = APN_ENABLED ? new apn.Provider({ token: { key, - keyId: 'key-id', - teamId: 'developer-team-id', + keyId: nconf.get('PUSH_CONFIGS:APN_KEY_ID'), + teamId: nconf.get('PUSH_CONFIGS:APN_TEAM_ID'), }, production: nconf.get('IS_PROD'), }) : undefined;