Skip to content

Commit 4bfc70d

Browse files
committed
Handle multiple failed decryption calls better
1 parent 0e178e8 commit 4bfc70d

File tree

4 files changed

+76
-36
lines changed

4 files changed

+76
-36
lines changed

src/main/java/com/pusher/client/channel/PrivateEncryptedChannelEventListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
*/
77
public interface PrivateEncryptedChannelEventListener extends PrivateChannelEventListener {
88

9-
void onDecryptionFailure(Exception e);
9+
void onDecryptionFailure(String event, String reason);
1010
}

src/main/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImpl.java

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,43 +129,49 @@ public void updateState(ChannelState state) {
129129

130130
@Override
131131
public PusherEvent prepareEvent(String event, String message) {
132-
try {
133-
134-
Map receivedMessage = GSON.fromJson(message, Map.class);
135-
final String decryptedMessage = decryptMessage((String) receivedMessage.get("data"));
136-
receivedMessage.replace("data", decryptedMessage);
137-
138-
return GSON.fromJson(
139-
GSON.toJson(receivedMessage), PusherEvent.class);
140132

141-
} catch (AuthenticityException e1) {
142-
143-
// retry once only.
144-
disposeSecretBoxOpener();
145-
authenticate();
133+
if (secretBoxOpener == null) {
134+
notifyListenersOfDecryptFailure(event, "Too many failed attempts to decrypt a previous message.");
135+
} else {
146136

147137
try {
138+
148139
Map receivedMessage = GSON.fromJson(message, Map.class);
149140
final String decryptedMessage = decryptMessage((String) receivedMessage.get("data"));
150141
receivedMessage.replace("data", decryptedMessage);
151142

152143
return GSON.fromJson(
153144
GSON.toJson(receivedMessage), PusherEvent.class);
154-
} catch (AuthenticityException e2) {
145+
146+
} catch (AuthenticityException e1) {
147+
148+
// retry once only.
155149
disposeSecretBoxOpener();
156-
notifyListenersOfDecryptFailure(event);
150+
authenticate();
151+
152+
try {
153+
Map receivedMessage = GSON.fromJson(message, Map.class);
154+
final String decryptedMessage = decryptMessage((String) receivedMessage.get("data"));
155+
receivedMessage.replace("data", decryptedMessage);
156+
157+
return GSON.fromJson(
158+
GSON.toJson(receivedMessage), PusherEvent.class);
159+
} catch (AuthenticityException e2) {
160+
disposeSecretBoxOpener();
161+
notifyListenersOfDecryptFailure(event, "Failed to decrypt message.");
162+
}
157163
}
164+
158165
}
159-
160166
return null;
161167
}
162168

163-
private void notifyListenersOfDecryptFailure(final String event) {
169+
private void notifyListenersOfDecryptFailure(final String event, final String reason) {
164170
Set<SubscriptionEventListener> listeners = getInterestedListeners(event);
165171
if (listeners != null) {
166172
for (SubscriptionEventListener listener : listeners) {
167173
((PrivateEncryptedChannelEventListener)listener).onDecryptionFailure(
168-
new Exception("Failed to decrypt message"));
174+
event, reason);
169175
}
170176
}
171177
}

src/main/java/com/pusher/client/example/PrivateEncryptedChannelExampleApp.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ public void onError(String message, String code, Exception e) {
8888
}
8989

9090
@Override
91-
public void onDecryptionFailure(Exception e) {
91+
public void onDecryptionFailure(String event, String reason) {
9292
System.out.println(String.format(
93-
"An error was received decrypting message - exception: [%s]", e));
93+
"An error was received decrypting message for event:[%s] - reason: [%s]", event, reason));
9494
}
9595
}

src/test/java/com/pusher/client/channel/impl/PrivateEncryptedChannelImplTest.java

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
package com.pusher.client.channel.impl;
22

3-
import static org.junit.Assert.assertEquals;
4-
import static org.mockito.Matchers.any;
5-
import static org.mockito.Matchers.anyString;
6-
import static org.mockito.Matchers.eq;
7-
import static org.mockito.Mockito.mock;
8-
import static org.mockito.Mockito.times;
9-
import static org.mockito.Mockito.verify;
10-
import static org.mockito.Mockito.when;
11-
123
import com.pusher.client.AuthorizationFailureException;
134
import com.pusher.client.Authorizer;
145
import com.pusher.client.channel.ChannelEventListener;
@@ -21,12 +12,19 @@
2112
import org.junit.Before;
2213
import org.junit.Test;
2314
import org.junit.runner.RunWith;
24-
import org.mockito.ArgumentCaptor;
25-
import org.mockito.Captor;
2615
import org.mockito.Matchers;
2716
import org.mockito.Mock;
2817
import org.mockito.runners.MockitoJUnitRunner;
2918

19+
import static org.junit.Assert.assertEquals;
20+
import static org.mockito.Matchers.any;
21+
import static org.mockito.Matchers.anyString;
22+
import static org.mockito.Matchers.eq;
23+
import static org.mockito.Mockito.mock;
24+
import static org.mockito.Mockito.times;
25+
import static org.mockito.Mockito.verify;
26+
import static org.mockito.Mockito.when;
27+
3028
@RunWith(MockitoJUnitRunner.class)
3129
public class PrivateEncryptedChannelImplTest extends ChannelImplTest {
3230

@@ -45,9 +43,6 @@ public class PrivateEncryptedChannelImplTest extends ChannelImplTest {
4543
@Mock
4644
SecretBoxOpenerFactory mockSecretBoxOpenerFactory;
4745

48-
@Captor
49-
ArgumentCaptor<Exception> exceptionArgumentCaptor;
50-
5146
@Override
5247
@Before
5348
public void setUp() {
@@ -255,7 +250,7 @@ public void onMessageRaisesExceptionWhenFailingToDecryptTwice() {
255250
"\\\"ciphertext\\\": \\\"/GMESnFGlbNn01BuBjp31XYa3i9vZsGKR8fgR9EDhXKx3lzGiUD501A=\\\"" +
256251
"}\"}");
257252

258-
verify(mockListener1).onDecryptionFailure(exceptionArgumentCaptor.capture());
253+
verify(mockListener1).onDecryptionFailure(anyString(), anyString());
259254
}
260255

261256
@Test
@@ -288,4 +283,43 @@ public void onMessageRetriesDecryptionOnce() {
288283
assertEquals("{\"message\":\"hello world\"}", argCaptor.getValue().getData());
289284
}
290285

286+
@Test
287+
public void twoEventsReceivedWithIncorrectSharedSecret() {
288+
289+
PrivateEncryptedChannelImpl channel = new PrivateEncryptedChannelImpl(
290+
mockInternalConnection,
291+
getChannelName(),
292+
mockAuthorizer,
293+
factory,
294+
mockSecretBoxOpenerFactory);
295+
296+
when(mockAuthorizer.authorize(Matchers.anyString(), Matchers.anyString()))
297+
.thenReturn(AUTH_RESPONSE_INCORRECT_SHARED_SECRET)
298+
.thenReturn(AUTH_RESPONSE_INCORRECT_SHARED_SECRET)
299+
.thenReturn(AUTH_RESPONSE_INCORRECT_SHARED_SECRET);
300+
when(mockSecretBoxOpenerFactory.create(any()))
301+
.thenReturn(new SecretBoxOpener(Base64.decode(SHARED_SECRET_INCORRECT)))
302+
.thenReturn(new SecretBoxOpener(Base64.decode(SHARED_SECRET_INCORRECT)))
303+
.thenReturn(new SecretBoxOpener(Base64.decode(SHARED_SECRET_INCORRECT)));
304+
305+
channel.toSubscribeMessage();
306+
307+
PrivateEncryptedChannelEventListener mockListener1 = mock(PrivateEncryptedChannelEventListener.class);
308+
channel.bind("my-event", mockListener1);
309+
channel.onMessage("my-event", "{\"event\":\"event1\",\"data\":\"{" +
310+
"\\\"nonce\\\": \\\"4sVYwy4j/8dCcjyxtPCWyk19GaaViaW9\\\"," +
311+
"\\\"ciphertext\\\": \\\"/GMESnFGlbNn01BuBjp31XYa3i9vZsGKR8fgR9EDhXKx3lzGiUD501A=\\\"" +
312+
"}\"}");
313+
314+
verify(mockListener1).onDecryptionFailure("my-event", "Failed to decrypt message.");
315+
316+
// send a second message
317+
channel.onMessage("my-event", "{\"event\":\"event1\",\"data\":\"{" +
318+
"\\\"nonce\\\": \\\"4sVYwy4j/8dCcjyxtPCWyk19GaaViaW9\\\"," +
319+
"\\\"ciphertext\\\": \\\"/GMESnFGlbNn01BuBjp31XYa3i9vZsGKR8fgR9EDhXKx3lzGiUD501A=\\\"" +
320+
"}\"}");
321+
322+
verify(mockListener1).onDecryptionFailure("my-event", "Too many failed attempts to decrypt a previous message.");
323+
}
324+
291325
}

0 commit comments

Comments
 (0)