junian / Standard.Licensing

Easy-to-use licensing library for .NET Framework, Mono, .NET Core, and MAUI / Xamarin products
https://junian.dev/Standard.Licensing/
MIT License
554 stars 127 forks source link

Multiple enumeration of AssertValidLicense results in incorrect validation #28

Closed AntiGuideAkquinet closed 6 months ago

AntiGuideAkquinet commented 1 year ago

When given an invalid license, AssertValidLicense returns an IEnumerable with a ValidationFailure on the first enumeration but an empty IEnumerable on the second enumeration.

As a workaround, I suggest users of the library use ToArray or alike to enumerate the IEnumerable only once.

The reason for this behavior is the current implementation of the validators collection in ValidationChainBuilder as a queue. In AssertValidLicense, all validators will be dequeued every time, resulting in different results.

I suggest either the usage of a list or the change of AssertValidLicense behavior to throw instead of returning failures. The name indicates a throw on invalid licenses and could potentially be dangerous to people relying on the implied behavior.

using Standard.Licensing;
using Standard.Licensing.Validation;

var keyGenerator = Standard.Licensing.Security.Cryptography.KeyGenerator.Create();
var keyPair = keyGenerator.GenerateKeyPair();
var publicKey = keyPair.ToPublicKeyString();

var invalidLicense = @"<License>
  <Signature>WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFg=</Signature>
</License>";

var licenseToVerify = License.Load(invalidLicense);

var validationFailures = licenseToVerify
    .Validate()
    .Signature(publicKey)
    .AssertValidLicense();

Console.WriteLine("validationFailures.Length: " + validationFailures.ToArray().Length);
Console.WriteLine("validationFailures.Length: " + validationFailures.ToArray().Length);

// validationFailures.Length: 1
// validationFailures.Length: 0
skst commented 6 months ago

Closing this issue means that the following line in the README.md can be deleted. (I didn't think it was worth a pull request, but I'm happy to create one if that's preferred.) 🙂

Make sure to call validationFailures.ToList() or validationFailures.ToArray() before using the result multiple times.