コード例 #1
0
ファイル: CipherEncoder.cs プロジェクト: ably/ably-dotnet
        public override Result <ProcessedPayload> Encode(IPayload payload, DecodingContext context)
        {
            var options        = context.ChannelOptions;
            var currentPayload = new ProcessedPayload(payload);

            if (IsEmpty(payload.Data) || IsEncrypted(currentPayload))
            {
                return(Result.Ok(new ProcessedPayload(currentPayload)));
            }

            if (options.Encrypted == false)
            {
                return(Result.Ok(new ProcessedPayload(currentPayload)));
            }

            if (currentPayload.Data is string data)
            {
                currentPayload.Data     = data.GetBytes();
                currentPayload.Encoding = AddEncoding(payload, "utf-8");
            }

            var cipher = Crypto.GetCipher(options.CipherParams);
            var result = new ProcessedPayload(
                cipher.Encrypt(currentPayload.Data as byte[]),
                AddEncoding(currentPayload, $"{EncodingName}+{options.CipherParams.CipherType.ToLower()}"));

            return(Result.Ok(result));
        }
コード例 #2
0
        internal static Result EncodePayloads(DecodingContext context, IEnumerable <IMessage> payloads)
        {
            var result = Result.Ok();

            foreach (var payload in payloads)
            {
                result = Result.Combine(result, EncodePayload(payload, context));
            }

            return(result);
        }
コード例 #3
0
        private static Result DecodePayloads(DecodingContext context, IEnumerable <IMessage> payloads, IEnumerable <MessageEncoder> encoders = null)
        {
            var result = Result.Ok();

            foreach (var payload in payloads)
            {
                result = Result.Combine(result, DecodePayload(payload, context, encoders));
            }

            return(result);
        }
コード例 #4
0
        public Result EncodeProtocolMessage(ProtocolMessage protocolMessage, DecodingContext context)
        {
            var result = Result.Ok();

            if (protocolMessage.Messages != null)
            {
                result = Result.Combine(EncodePayloads(context, protocolMessage.Messages));
            }

            if (protocolMessage.Presence != null)
            {
                result = Result.Combine(EncodePayloads(context, protocolMessage.Presence));
            }

            return(result);
        }
コード例 #5
0
        public override Result <ProcessedPayload> Encode(IPayload payload, DecodingContext context)
        {
            if (IsEmpty(payload.Data))
            {
                return(Result.Ok(new ProcessedPayload(payload)));
            }

            if (NeedsJsonEncoding(payload))
            {
                return(Result.Ok(new ProcessedPayload(
                                     JsonHelper.Serialize(payload.Data),
                                     AddEncoding(payload, EncodingName))));
            }

            return(Result.Ok(new ProcessedPayload(payload)));
        }
コード例 #6
0
        private IEnumerable <Message> ParseMessagesResponse(AblyResponse response, DecodingContext context)
        {
            if (response.Type == ResponseType.Json)
            {
                var messages = JsonHelper.Deserialize <List <Message> >(response.TextResponse);
                ProcessMessages(messages, context);
                return(messages);
            }

#if MSGPACK
            var payloads = MsgPackHelper.Deserialise(response.Body, typeof(List <Message>)) as List <Message>;
            ProcessMessages(payloads, options);
            return(payloads);
#else
            throw new AblyException($"Response of type '{response.Type}' is invalid because MsgPack support was not enabled for this build.");
#endif
        }
コード例 #7
0
ファイル: CipherEncoder.cs プロジェクト: ably/ably-dotnet
        public override Result <ProcessedPayload> Decode(IPayload payload, DecodingContext context)
        {
            var options = context.ChannelOptions;
            var logger  = options?.Logger ?? DefaultLogger.LoggerInstance;

            if (IsEmpty(payload.Data))
            {
                return(Result.Ok(new ProcessedPayload(payload)));
            }

            var currentEncoding = GetCurrentEncoding(payload);

            if (currentEncoding.Contains(EncodingName) == false)
            {
                return(Result.Ok(new ProcessedPayload(payload)));
            }

            var cipherType = GetCipherType(currentEncoding);

            if (cipherType.EqualsTo(options.CipherParams.CipherType) == false)
            {
                logger.Error(
                    $"Cipher algorithm {options.CipherParams.CipherType.ToLower()} does not match message cipher algorithm of {currentEncoding}");
                return(Result.Fail <ProcessedPayload>(new ErrorInfo($"Cipher algorithm {options.CipherParams.CipherType.ToLower()} does not match message cipher algorithm of {currentEncoding}")));
            }

            var cipher = Crypto.GetCipher(options.CipherParams);

            try
            {
                if (payload.Data is byte[] == false)
                {
                    return(Result.Fail <ProcessedPayload>(new ErrorInfo("Expected data to be byte[] but received " + payload.Data.GetType())));
                }

                return(Result.Ok(new ProcessedPayload(
                                     payload.Data = cipher.Decrypt(payload.Data as byte[]),
                                     RemoveCurrentEncodingPart(payload))));
            }
            catch (AblyException ex)
            {
                logger.Error($"Error decrypting payload using cypher {options.CipherParams.CipherType}. Leaving it encrypted", ex);
                return(Result.Fail <ProcessedPayload>(new ErrorInfo($"Error decrypting payload using cypher {options.CipherParams.CipherType}. Leaving it encrypted")));
            }
        }
コード例 #8
0
        public Result DecodeMessages(
            ProtocolMessage protocolMessage,
            IEnumerable <IMessage> messages,
            DecodingContext context)
        {
            var result = Result.Ok();
            var index  = 0;

            foreach (var message in messages ?? Enumerable.Empty <IMessage>())
            {
                SetMessageIdConnectionIdAndTimestamp(message, index);
                var decodeResult = DecodePayload(message, context, DefaultEncoders)
                                   .IfFailure(error => Logger.Warning($"Error decoding message with id: {message.Id}. Error: {error.Message}. Exception: {error.InnerException?.Message}"));

                result = Result.Combine(result, decodeResult);

                if (result.IsFailure)
                {
                    break;
                }

                index++;
            }

            return(result);

            void SetMessageIdConnectionIdAndTimestamp(IMessage message, int i)
            {
                if (message.Id.IsEmpty())
                {
                    message.Id = $"{protocolMessage.Id}:{i}";
                }

                if (message.ConnectionId.IsEmpty())
                {
                    message.ConnectionId = protocolMessage.ConnectionId;
                }

                if (message.Timestamp.HasValue == false)
                {
                    message.Timestamp = protocolMessage.Timestamp;
                }
            }
        }
コード例 #9
0
        public override Result <ProcessedPayload> Decode(IPayload payload, DecodingContext context)
        {
            var options = context.ChannelOptions;
            var logger  = options?.Logger ?? DefaultLogger.LoggerInstance;

            if (IsEmpty(payload.Data) || !CurrentEncodingIs(payload, EncodingName))
            {
                return(Result.Ok(new ProcessedPayload(payload)));
            }

            try
            {
                return(Result.Ok(new ProcessedPayload(
                                     JsonHelper.Deserialize(payload.Data as string),
                                     RemoveCurrentEncodingPart(payload))));
            }
            catch (Exception ex)
            {
                logger.Error($"Invalid Json data: '{payload.Data}'", ex);
                return(Result.Fail <ProcessedPayload>(new ErrorInfo($"Invalid Json data: '{payload.Data}'")));
            }
        }
コード例 #10
0
        internal static Result EncodePayload(IMessage payload, DecodingContext context, IEnumerable <MessageEncoder> encoders = null)
        {
            ValidatePayloadDataType(payload);
            var result = Result.Ok();

            foreach (var encoder in encoders ?? DefaultEncoders)
            {
                var encodeResult = encoder.Encode(payload, context);
                if (encodeResult.IsSuccess)
                {
                    payload.Data     = encodeResult.Value.Data;
                    payload.Encoding = encodeResult.Value.Encoding;
                }

                result = Result.Combine(result, encodeResult);

                if (result.IsFailure)
                {
                    break;
                }
            }

            return(result);
        }
コード例 #11
0
 private static void ProcessMessages <T>(IEnumerable <T> payloads, DecodingContext context) where T : IMessage
 {
     // TODO: What happens with rest request where we can't decode messages
     _ = DecodePayloads(context, payloads as IEnumerable <IMessage>);
 }
コード例 #12
0
        internal static Result DecodePayload(IMessage payload, DecodingContext context, IEnumerable <MessageEncoder> encoders = null, ILogger logger = null)
        {
            var actualEncoders = (encoders ?? DefaultEncoders).ToList();
            var pp             = context.PreviousPayload; // We take a chance that this will not be modified but replaced

            var(processResult, decodedPayload) = Decode();

            // None of the encoders updated the PreviousPayload
            // then we need to set the default one
            Result overallResult = processResult;

            if (pp == context.PreviousPayload)
            {
                var originalPayloadResult = GetOriginalMessagePayload();
                _ = originalPayloadResult.IfSuccess(x =>
                {
                    context.PreviousPayload = x;
                });
                overallResult = Result.Combine(overallResult, originalPayloadResult);
            }

            payload.Data     = decodedPayload.Data;
            payload.Encoding = decodedPayload.Encoding;

            return(overallResult);

            Result <PayloadCache> GetOriginalMessagePayload()
            {
                if (payload.Data is byte[] data)
                {
                    return(Result.Ok(new PayloadCache(data, payload.Encoding)));
                }

                bool isFirstEncodingBase64 = MessageEncoder.CurrentEncodingIs(payload, Base64Encoder.EncodingNameStr);

                if (isFirstEncodingBase64)
                {
                    var result = Base64Encoder.Decode(payload, new DecodingContext());
                    return(result.Map(x => new PayloadCache((byte[])x.Data, MessageEncoder.RemoveCurrentEncodingPart(payload))));
                }

                return(Result.Ok(new PayloadCache((string)payload.Data, payload.Encoding)));
            }

            // Local function that tidies the processing
            // the first part of the tuple will return the result. We don't have `true` or `false` because
            // we care about the error message that came from the encoder that failed.
            // The processed payload is returned separately so we can still update the message.
            (Result <Unit> processResult, IPayload processedPayload) Decode()
            {
                int processedEncodings = 0;
                var numberOfEncodings  = payload.Encoding.IsNotEmpty() ? payload.Encoding.Count(x => x == '/') + 1 : 0;

                if (numberOfEncodings == 0 || payload.Data == null)
                {
                    return(Result.Ok(Unit.Default), payload);
                }

                IPayload currentPayload = payload;

                while (true)
                {
                    var currentEncoding = MessageEncoder.GetCurrentEncoding(currentPayload);
                    if (currentEncoding.IsEmpty())
                    {
                        return(Result.Ok(Unit.Default), currentPayload);
                    }

                    var decoder = actualEncoders.FirstOrDefault(x => x.CanProcess(currentEncoding));
                    if (decoder == null)
                    {
                        logger?.Warning($"Missing decoder for '{currentEncoding}'. Leaving as it is");
                        return(Result.Ok(Unit.Default), currentPayload);
                    }

                    var result = decoder.Decode(currentPayload, context);

                    if (result.IsSuccess)
                    {
                        currentPayload = result.Value;
                    }
                    else
                    {
                        // If an encoder fails we want to return the result up to this encoder
                        return(Result.Fail <Unit>(result), currentPayload);
                    }

                    // just to be safe
                    if (processedEncodings > numberOfEncodings)
                    {
                        // TODO: Send to Sentry
                        return(Result.Fail <Unit>(new ErrorInfo("Failed to decode message encoding")), currentPayload);
                    }

                    processedEncodings++;
                }
            }
        }
コード例 #13
0
        public override Result <ProcessedPayload> Decode(IPayload payload, DecodingContext context)
        {
            var logger = context.ChannelOptions?.Logger ?? DefaultLogger.LoggerInstance;

            if (payload == null)
            {
                return(Result.Ok(new ProcessedPayload()));
            }

            try
            {
                var payloadBytes = DataHelpers.ConvertToByteArray(payload.Data);

                var previousPayload = context.PreviousPayload?.GetBytes();
                if (previousPayload is null)
                {
                    return(Result.Fail <ProcessedPayload>(new VcDiffErrorInfo("Missing previous payload")));
                }

                var result       = DeltaDecoder.ApplyDelta(previousPayload, payloadBytes);
                var nextEncoding = RemoveCurrentEncodingPart(payload);

                context.PreviousPayload = new PayloadCache(result.AsByteArray(), nextEncoding);
                return(Result.Ok(new ProcessedPayload(
                                     result.AsByteArray(),
                                     RemoveCurrentEncodingPart(payload))));
            }
            catch (Exception ex)
            {
                var error =
                    $"Payload Encoding: {payload.Encoding}. Payload data: {GetPayloadString()}";
                logger.Error("Error decoding vcdiff message: " + error, ex);

                return(Result.Fail <ProcessedPayload>(new VcDiffErrorInfo("Failed to decode vcdiff message", ex)));
            }

            string GetPayloadString()
            {
                try
                {
                    if (payload.Data == null)
                    {
                        return("null");
                    }

                    if (payload.Data is byte[])
                    {
                        return((payload.Data as byte[]).ToBase64());
                    }

                    if (payload.Data is string)
                    {
                        return(payload.Data as string);
                    }

                    return(string.Empty);
                }
                catch
                {
                    return(string.Empty);
                }
            }
        }
コード例 #14
0
 public override Result <ProcessedPayload> Encode(IPayload payload, DecodingContext context)
 {
     return(Result.Ok(new ProcessedPayload(payload)));
 }
コード例 #15
0
ファイル: MessageEncoder.cs プロジェクト: ably/ably-dotnet
 public abstract Result <ProcessedPayload> Decode(IPayload payload, DecodingContext context);