public string DecryptData(byte[] decryptionKey, EncryptedChannelData encryptedData)
        {
            string decryptedText = null;

            byte[] cipher = null;
            byte[] nonce  = null;
            if (encryptedData != null)
            {
                if (encryptedData.ciphertext != null)
                {
                    cipher = Convert.FromBase64String(encryptedData.ciphertext);
                }

                if (encryptedData.nonce != null)
                {
                    nonce = Convert.FromBase64String(encryptedData.nonce);
                }
            }

            if (cipher != null && nonce != null)
            {
                using (XSalsa20Poly1305 secretBox = new XSalsa20Poly1305(decryptionKey))
                {
                    byte[] decryptedBytes = new byte[cipher.Length - XSalsa20Poly1305.TagLength];
                    if (secretBox.TryDecrypt(decryptedBytes, cipher, nonce))
                    {
                        decryptedText = Encoding.UTF8.GetString(decryptedBytes);
                    }
                    else
                    {
                        throw new ChannelDecryptionException("Decryption failed for channel.");
                    }
                }
            }
            else
            {
                throw new ChannelDecryptionException("Insufficient data received; requires encrypted data with 'ciphertext' and 'nonce'.");
            }

            return(decryptedText);
        }
Example #2
0
        private void WebsocketMessageReceived(object sender, MessageReceivedEventArgs e)
        {
            string eventName   = null;
            string channelName = null;

            try
            {
                if (_pusher.PusherOptions.TraceLogger != null)
                {
                    _pusher.PusherOptions.TraceLogger.TraceInformation($"Websocket message received:{Environment.NewLine}{e.Message}");
                }

                JObject jObject = JObject.Parse(e.Message);
                string  rawJson = jObject.ToString(Formatting.None);
                Dictionary <string, object> message = GetEventPropertiesFromMessage(rawJson);
                if (message.ContainsKey("event"))
                {
                    eventName = (string)message["event"];

                    if (eventName == Constants.ERROR)
                    {
                        /*
                         *  Errors are in a different Json form to other messages.
                         *  The data property is an object and not a string and needs to be dealt with differently; for example:
                         *  {"event":"pusher:error","data":{"code":4001,"message":"App key Invalid not in this cluster. Did you forget to specify the cluster?"}}
                         */
                        ParseError(jObject["data"]);
                    }
                    else
                    {
                        /*
                         *  For messages other than "pusher:error" the data property is a string; for example:
                         *  {
                         *    "event": "pusher:connection_established",
                         *    "data": "{\"socket_id\":\"131160.155806628\"}"
                         *  }
                         *
                         *  {
                         *    "event": "pusher_internal:subscription_succeeded",
                         *    "data": "{\"presence\":{\"count\":1,\"ids\":[\"131160.155806628\"],\"hash\":{\"131160.155806628\":{\"name\":\"user-1\"}}}}",
                         *    "channel": "presence-channel-1"
                         *  }
                         */
                        string messageData = string.Empty;
                        if (message.ContainsKey("data"))
                        {
                            messageData = (string)message["data"];
                        }

                        if (message.ContainsKey("channel"))
                        {
                            channelName = (string)message["channel"];
                            if (!ProcessPusherChannelEvent(eventName, channelName, messageData))
                            {
                                byte[] decryptionKey = _pusher.GetSharedSecret(channelName);
                                if (decryptionKey != null)
                                {
                                    message["data"] = _dataDecrypter.DecryptData(decryptionKey, EncryptedChannelData.CreateFromJson(messageData));
                                }

                                EmitEvent(eventName, rawJson, message);
                                EmitChannelEvent(eventName, rawJson, channelName, message);
                            }
                        }
                        else
                        {
                            ProcessPusherEvent(eventName, messageData);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                string          operation = nameof(WebsocketMessageReceived);
                PusherException error;
                if (channelName != null)
                {
                    if (exception is ChannelException channelException)
                    {
                        channelException.ChannelName = channelName;
                        channelException.EventName   = eventName;
                        channelException.SocketID    = SocketId;
                        error = channelException;
                    }
                    else
                    {
                        error = new ChannelException($"An unexpected error was detected when performing the operation '{operation}'", ErrorCodes.MessageReceivedError, channelName, SocketId, exception)
                        {
                            EventName = eventName,
                        };
                    }
                }
                else
                {
                    if (eventName != null)
                    {
                        operation += $" for event '{eventName}'";
                    }

                    error = new OperationException(ErrorCodes.MessageReceivedError, operation, exception);
                }

                RaiseError(error);
            }
        }