66import com .pusher .client .channel .PrivateEncryptedChannel ;
77import com .pusher .client .channel .PrivateEncryptedChannelEventListener ;
88import com .pusher .client .channel .SubscriptionEventListener ;
9+ import com .pusher .client .connection .ConnectionEventListener ;
10+ import com .pusher .client .connection .ConnectionState ;
11+ import com .pusher .client .connection .ConnectionStateChange ;
912import com .pusher .client .connection .impl .InternalConnection ;
1013import com .pusher .client .crypto .nacl .SecretBoxOpener ;
1114import com .pusher .client .crypto .nacl .SecretBoxOpenerFactory ;
@@ -22,6 +25,23 @@ public class PrivateEncryptedChannelImpl extends ChannelImpl implements PrivateE
2225 private SecretBoxOpenerFactory secretBoxOpenerFactory ;
2326 private SecretBoxOpener secretBoxOpener ;
2427
28+ // For not hanging on to shared secret past the Pusher.disconnect() call,
29+ // i.e. when not necessary. Pusher.connect(...) call will trigger re-subscribe
30+ // and hence re-authenticate which creates a new secretBoxOpener.
31+ private ConnectionEventListener disposeSecretBoxOpenerOnDisconnectedListener =
32+ new ConnectionEventListener () {
33+
34+ @ Override
35+ public void onConnectionStateChange (ConnectionStateChange change ) {
36+ disposeSecretBoxOpener ();
37+ }
38+
39+ @ Override
40+ public void onError (String message , String code , Exception e ) {
41+ // nop
42+ }
43+ };
44+
2545 public PrivateEncryptedChannelImpl (final InternalConnection connection ,
2646 final String channelName ,
2747 final Authorizer authorizer ,
@@ -45,22 +65,38 @@ public void bind(final String eventName, final SubscriptionEventListener listene
4565 super .bind (eventName , listener );
4666 }
4767
48- private String authenticate () {
68+ @ Override
69+ public String toSubscribeMessage () {
70+ String authKey = authenticate ();
71+
72+ // create the data part
73+ final Map <Object , Object > dataMap = new LinkedHashMap <>();
74+ dataMap .put ("channel" , name );
75+ dataMap .put ("auth" , authKey );
76+
77+ // create the wrapper part
78+ final Map <Object , Object > jsonObject = new LinkedHashMap <>();
79+ jsonObject .put ("event" , "pusher:subscribe" );
80+ jsonObject .put ("data" , dataMap );
81+
82+ return GSON .toJson (jsonObject );
83+ }
4984
85+ private String authenticate () {
5086 try {
51- final Map authResponseMap = GSON .fromJson (getAuthResponse (), Map .class );
52- final String auth = (String ) authResponseMap .get ("auth" );
53- final String sharedSecret = (String ) authResponseMap .get ("shared_secret" );
87+ @ SuppressWarnings ("rawtypes" ) // anything goes in JS
88+ final Map authResponse = GSON .fromJson (getAuthResponse (), Map .class );
89+
90+ final String auth = (String ) authResponse .get ("auth" );
91+ final String sharedSecret = (String ) authResponse .get ("shared_secret" );
5492
5593 if (auth == null || sharedSecret == null ) {
5694 throw new AuthorizationFailureException ("Didn't receive all the fields expected " +
5795 "from the Authorizer, expected an auth and shared_secret." );
5896 } else {
59- secretBoxOpener = secretBoxOpenerFactory .create (
60- Base64 .decode (sharedSecret ));
97+ createSecretBoxOpener (Base64 .decode (sharedSecret ));
6198 return auth ;
6299 }
63-
64100 } catch (final AuthorizationFailureException e ) {
65101 throw e ; // pass this upwards
66102 } catch (final Exception e ) {
@@ -69,39 +105,38 @@ private String authenticate() {
69105 }
70106 }
71107
72- @ Override
73- public String toSubscribeMessage () {
74-
75- String authKey = authenticate ();
76-
77- // create the data part
78- final Map <Object , Object > dataMap = new LinkedHashMap <Object , Object >();
79- dataMap .put ("channel" , name );
80- dataMap .put ("auth" , authKey );
81-
82- // create the wrapper part
83- final Map <Object , Object > jsonObject = new LinkedHashMap <Object , Object >();
84- jsonObject .put ("event" , "pusher:subscribe" );
85- jsonObject .put ("data" , dataMap );
108+ private void createSecretBoxOpener (byte [] key ) {
109+ secretBoxOpener = secretBoxOpenerFactory .create (key );
110+ setListenerToDisposeSecretBoxOpenerOnDisconnected ();
111+ }
86112
87- return GSON .toJson (jsonObject );
113+ private void setListenerToDisposeSecretBoxOpenerOnDisconnected () {
114+ connection .bind (ConnectionState .DISCONNECTED ,
115+ disposeSecretBoxOpenerOnDisconnectedListener );
88116 }
89117
90118 @ Override
91119 public void updateState (ChannelState state ) {
92120 super .updateState (state );
93121
94122 if (state == ChannelState .UNSUBSCRIBED ) {
95- tearDownChannel ();
123+ disposeSecretBoxOpener ();
96124 }
97125 }
98126
99- private void tearDownChannel () {
127+ private void disposeSecretBoxOpener () {
100128 if (secretBoxOpener != null ) {
101129 secretBoxOpener .clearKey ();
130+ secretBoxOpener = null ;
131+ removeListenerToDisposeSecretBoxOpenerOnDisconnected ();
102132 }
103133 }
104134
135+ private void removeListenerToDisposeSecretBoxOpenerOnDisconnected () {
136+ connection .unbind (ConnectionState .DISCONNECTED ,
137+ disposeSecretBoxOpenerOnDisconnectedListener );
138+ }
139+
105140 private String getAuthResponse () {
106141 final String socketId = connection .getSocketId ();
107142 return authorizer .authorize (getName (), socketId );
0 commit comments