Repository: cal-itp/benefits

Issue:
Model eligibility verification form field validation
Our current practice has been to offload input validation to the Eligibility Server, since we're simply a pass-through for rules and data defined there.

However this creates at least a couple potential issues:

* The user must submit their information before they know if it's formatted incorrectly, vs. immediate in-browser feedback
* The fields allow for any size and type of value, a potential DDoS vector

Given we will have more than one `EligibilityVerifier` in the next phase, each with unique form validation needs and UX considerations, now is the time to implement Eligibility verification form field validation.

## Tasks

* [x] Add a `TextField` or similar to the `EligibilityVerifier` model that captures a regex pattern that can be used to validate the `sub` field in the [eligibility verification form](https://github.com/cal-itp/benefits/blob/dev/benefits/eligibility/forms.py#L15).
* [x] Add a `PositiveIntegerField` or similar to the `EligibilityVerifier` model that captures the maximum allowed length for the `name` field in the form.


Discussion:

Resolving patch:
diff --git a/benefits/core/migrations/0001_initial.py b/benefits/core/migrations/0001_initial.py
--- a/benefits/core/migrations/0001_initial.py
+++ b/benefits/core/migrations/0001_initial.py
@@ -34,6 +34,8 @@ class Migration(migrations.Migration):
                 ("api_auth_header", models.TextField()),
                 ("api_auth_key", models.TextField()),
                 # fmt: off
+                ("sub_regex", models.TextField(help_text="A regular expression used to validate the 'sub' API field before sending to this verifier", null=True)),  # noqa: E501
+                ("name_max_length", models.PositiveSmallIntegerField(help_text="The maximum length accepted for the 'name' API field before sending to this verifier", null=True)),  # noqa: E501
                 ("public_key", models.ForeignKey(help_text="The Verifier's public key, used to encrypt requests targeted at this Verifier and to verify signed responses from this verifier.", on_delete=models.deletion.PROTECT, related_name="+", to="core.PemData")),  # noqa: E501
                 ("jwe_cek_enc", models.TextField(help_text="The JWE-compatible Content Encryption Key (CEK) key-length and mode")),  # noqa: E501
                 ("jwe_encryption_alg", models.TextField(help_text="The JWE-compatible encryption algorithm")),
diff --git a/benefits/core/models.py b/benefits/core/models.py
--- a/benefits/core/models.py
+++ b/benefits/core/models.py
@@ -67,6 +67,8 @@ class EligibilityVerifier(models.Model):
     jwe_cek_enc = models.TextField(help_text="The JWE-compatible Content Encryption Key (CEK) key-length and mode")
     jwe_encryption_alg = models.TextField(help_text="The JWE-compatible encryption algorithm")
     jws_signing_alg = models.TextField(help_text="The JWS-compatible signing algorithm")
+    sub_regex = models.TextField(null=True, help_text="A regular expression used to validate the 'sub' API field before sending to this verifier")  # noqa: 503
+    name_max_length = models.PositiveSmallIntegerField(null=True, help_text="The maximum length accepted for the 'name' API field before sending to this verifier")  # noqa: 503
     # fmt: on
 
     def __str__(self):


Test patch: