Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/392 fix and improve payment payload generator validation #498

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions QRCoder/PayloadGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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));
}


Expand Down
28 changes: 24 additions & 4 deletions QRCoderTests/PayloadGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PayloadGenerator.RussiaPaymentOrder.RussiaPaymentOrderException>(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<PayloadGenerator.RussiaPaymentOrder.RussiaPaymentOrderException>(exception);
exception.Message.ShouldStartWith("Data too long");
Assert.Null(exception);
}

[Fact]
Expand Down
Loading