From 39fadf978c9e9891779f5ac09b53a1a257c05929 Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Tue, 23 Apr 2024 22:46:17 +0200 Subject: [PATCH 1/2] Fixed validation logic in PaymentOrder generator --- QRCoder/PayloadGenerator.cs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/QRCoder/PayloadGenerator.cs b/QRCoder/PayloadGenerator.cs index e282a580..56949682 100644 --- a/QRCoder/PayloadGenerator.cs +++ b/QRCoder/PayloadGenerator.cs @@ -2512,6 +2512,13 @@ public override string ToString() public byte[] ToBytes() { + //Setup byte encoder + //Encode return string as byte[] with correct CharacterSet +#if !NET35_OR_GREATER + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); +#endif + var cp = this.characterSet.ToString().Replace("_", "-"); + //Calculate the seperator separator = DetermineSeparator(); @@ -2523,21 +2530,19 @@ public byte[] ToBytes() $"{separator}BIC={mFields.BIC}" + $"{separator}CorrespAcc={mFields.CorrespAcc}"; + //Check length of mandatory field block (-8 => Removing service data block bytes from ret length) + int bytesMandatoryLen = Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding(cp), Encoding.UTF8.GetBytes(ret)).Length - 8; + if (bytesMandatoryLen > 300) + throw new RussiaPaymentOrderException($"Data too long. Mandatory data must not exceed 300 bytes, but actually is {bytesMandatoryLen} bytes long. Remove additional data fields or shorten strings/values."); + + //Add optional fields, if filled var optionalFieldsList = GetOptionalFieldsAsList(); if (optionalFieldsList.Count > 0) ret += $"|{string.Join("|", optionalFieldsList.ToArray())}"; ret += separator; - //Encode return string as byte[] with correct CharacterSet -#if !NET35_OR_GREATER - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); -#endif - var cp = this.characterSet.ToString().Replace("_", "-"); - byte[] bytesOut = Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding(cp), Encoding.UTF8.GetBytes(ret)); - if (bytesOut.Length > 300) - throw new RussiaPaymentOrderException($"Data too long. Payload must not exceed 300 bytes, but actually is {bytesOut.Length} bytes long. Remove additional data fields or shorten strings/values."); - return bytesOut; + return Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding(cp), Encoding.UTF8.GetBytes(ret)); } From 25455b89157fe5ea7882eaef1e340cce18a5fe7d Mon Sep 17 00:00:00 2001 From: Raffael Herrmann Date: Tue, 23 Apr 2024 22:46:31 +0200 Subject: [PATCH 2/2] Updated and added testcase for PaymentOrder --- QRCoderTests/PayloadGeneratorTests.cs | 28 +++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/QRCoderTests/PayloadGeneratorTests.cs b/QRCoderTests/PayloadGeneratorTests.cs index a8bab5b2..717516e8 100644 --- a/QRCoderTests/PayloadGeneratorTests.cs +++ b/QRCoderTests/PayloadGeneratorTests.cs @@ -3280,24 +3280,44 @@ public void russiapayment_generator_should_throw_no_separator_exception() [Fact] [Category("PayloadGenerator/RussiaPaymentOrder")] public void russiapayment_generator_should_throw_data_too_long_exception() + { + var account = "40702810138250123017"; + var bic = "044525225"; + var bankName = "A very very very very very long bank name"; + // We use € symbol for the test case, because it needs 2-bytes. Otherwise we couldn't generate more than 300 bytes + // of mandatory data to trigger the test case and stay at the same time within the 160 chars field validation limit + var name = "A very €€€€ €€€€ €€€€ €€€€ very very very very very very very very very very very very very very very very very very very very very very very very ver long name"; + var correspAcc = "30101810400000000225"; + var generator = new PayloadGenerator.RussiaPaymentOrder(name, account, bankName, bic, correspAcc); + + var exception = Record.Exception(() => generator.ToString()); + Assert.NotNull(exception); + Assert.IsType(exception); + exception.Message.ShouldStartWith("Data too long"); + } + + [Fact] + [Category("PayloadGenerator/RussiaPaymentOrder")] + public void russiapayment_generator_should_throw_no_data_too_long_exception() { var account = "40702810138250123017"; var bic = "044525225"; var bankName = "ОАО | \"БАНК\""; - var name = "A very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long name"; + var name = "A name"; var correspAcc = "30101810400000000225"; var optionalFields = new PayloadGenerator.RussiaPaymentOrder.OptionalFields() { FirstName = "Another long long long long long long long long long long long long long long firstname", LastName = "Another long long long long long long long long long long long long long long lastname", + Category = "A pretty long long long long long long long long long long long long long category", Sum = "125000" }; var generator = new PayloadGenerator.RussiaPaymentOrder(name, account, bankName, bic, correspAcc, optionalFields); + // Should throw no exception as the 300 byte limit applies only to the mandatory fields + // See https://github.com/codebude/QRCoder/issues/392 var exception = Record.Exception(() => generator.ToString()); - Assert.NotNull(exception); - Assert.IsType(exception); - exception.Message.ShouldStartWith("Data too long"); + Assert.Null(exception); } [Fact]