diff --git a/src/client.js b/src/client.js index 79b0d7d..195643e 100644 --- a/src/client.js +++ b/src/client.js @@ -197,14 +197,8 @@ module.exports = class Client extends EventEmitter { ): case error.message.includes('crypto-key is missing'): case error.message.includes('salt is missing'): - // NOTE(ibash) Periodically we're unable to decrypt notifications. In - // all cases we've been able to receive future notifications using the - // same keys. So, we silently drop this notification. - console.warn( - 'Message dropped as it could not be decrypted: ' + error.message - ); this._persistentIds.push(object.persistentId); - return; + throw error; default: { throw error; } diff --git a/src/gcm/index.js b/src/gcm/index.js index 9260129..940082f 100644 --- a/src/gcm/index.js +++ b/src/gcm/index.js @@ -8,8 +8,8 @@ const { toBase64 } = require('../utils/base64'); // Hack to fix PHONE_REGISTRATION_ERROR #17 when bundled with webpack // https://github.com/dcodeIO/protobuf.js#browserify-integration -protobuf.util.Long = Long -protobuf.configure() +protobuf.util.Long = Long; +protobuf.configure(); const serverKey = toBase64(Buffer.from(fcmKey)); diff --git a/test/client.test.js b/test/client.test.js new file mode 100644 index 0000000..a19a481 --- /dev/null +++ b/test/client.test.js @@ -0,0 +1,86 @@ +jest.mock('../src/utils/decrypt'); + +const Client = require('../src/client'); +const decrypt = require('../src/utils/decrypt'); + +const KEYS = { + authSecret : 'auth-secret', + privateKey : 'private-key', +}; + +function createClient(persistentIds = []) { + return new Client({ keys : KEYS }, { persistentIds }); +} + +describe('Client', () => { + describe('_onDataMessage', () => { + beforeEach(() => { + decrypt.mockReset(); + }); + + [ + 'Unsupported state or unable to authenticate data', + 'crypto-key is missing', + 'salt is missing', + ].forEach(errorMessage => { + it(`raises "${errorMessage}" after recording the persistent id`, () => { + const client = createClient(); + const object = { persistentId : 'persistent-id' }; + const decryptionError = new Error(errorMessage); + let thrownError; + + decrypt.mockImplementation(() => { + throw decryptionError; + }); + + try { + client._onDataMessage(object); + } catch (error) { + thrownError = error; + } + + expect(thrownError).toBe(decryptionError); + expect(client._persistentIds).toEqual(['persistent-id']); + expect(decrypt).toHaveBeenCalledWith(object, KEYS); + }); + }); + + it('does not record unrelated decrypt errors', () => { + const client = createClient(); + const object = { persistentId : 'persistent-id' }; + const decryptionError = new Error('unexpected decrypt failure'); + let thrownError; + + decrypt.mockImplementation(() => { + throw decryptionError; + }); + + try { + client._onDataMessage(object); + } catch (error) { + thrownError = error; + } + + expect(thrownError).toBe(decryptionError); + expect(client._persistentIds).toEqual([]); + }); + + it('records and emits successfully decrypted messages', () => { + const client = createClient(); + const object = { persistentId : 'persistent-id' }; + const message = { title : 'Hello' }; + const onNotification = jest.fn(); + + decrypt.mockReturnValue(message); + client.on('ON_NOTIFICATION_RECEIVED', onNotification); + + client._onDataMessage(object); + + expect(client._persistentIds).toEqual(['persistent-id']); + expect(onNotification).toHaveBeenCalledWith({ + notification : message, + persistentId : 'persistent-id', + }); + }); + }); +});