Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions src/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions src/gcm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
86 changes: 86 additions & 0 deletions test/client.test.js
Original file line number Diff line number Diff line change
@@ -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',
});
});
});
});