diff options
Diffstat (limited to 'webmentions_ssg/forms')
| -rw-r--r-- | webmentions_ssg/forms/__init__.py | 15 | ||||
| -rw-r--r-- | webmentions_ssg/forms/validators.py | 88 |
2 files changed, 80 insertions, 23 deletions
diff --git a/webmentions_ssg/forms/__init__.py b/webmentions_ssg/forms/__init__.py index 7ab82e3..5d2f827 100644 --- a/webmentions_ssg/forms/__init__.py +++ b/webmentions_ssg/forms/__init__.py @@ -12,12 +12,23 @@ from .validators import AllowedHostname, NotEqualTo, PublicURL class LoginForm(FlaskForm): + """ + Form for authenticating a user. + """ + username = StringField("Username", validators=[InputRequired()]) password = PasswordField("Password", validators=[InputRequired()]) submit = SubmitField("Sign In") class EndpointForm(FlaskForm): + """ + Form for receiving a Webmention. + + The source must be a public HTTP or HTTPS URL distinct from the target. + The target must be an HTTP or HTTPS URL using an allowed hostname. + """ + source = StringField( "source", validators=[ @@ -48,4 +59,8 @@ class EndpointForm(FlaskForm): class AdminActionForm(FlaskForm): + """ + Form for confirming an administrative action. + """ + submit = SubmitField("Confirm") diff --git a/webmentions_ssg/forms/validators.py b/webmentions_ssg/forms/validators.py index fd54e0f..761dc46 100644 --- a/webmentions_ssg/forms/validators.py +++ b/webmentions_ssg/forms/validators.py @@ -5,28 +5,39 @@ from urllib.parse import urlsplit from flask import current_app -from wtforms import ValidationError +from wtforms import Field, ValidationError +from wtforms.form import BaseForm from ..url_security import AddressResolutionError, is_public_url class NotEqualTo: """ - Compares the values of two fields. + Validate that a field does not equal another field. - :param fieldname: - The name of the other field to compare to. - :param message: - Error message to raise in case of a validation error. Can be - interpolated with `%(other_label)s` and `%(other_name)s` to provide a - more helpful error. + :param fieldname: Name of the field to compare against. + :param message: Optional validation error message. """ - def __init__(self, fieldname, message=None): + def __init__(self, fieldname: str, message: str | None = None) -> None: + """ + Initialize the validator. + + :param fieldname: Name of the field to compare against. + :param message: Optional validation error message. + """ self.fieldname = fieldname self.message = message - def __call__(self, form, field): + def __call__(self, form: BaseForm, field: Field) -> None: + """ + Validate that two fields do not contain equal values. + + :param form: Form containing the fields to compare. + :param field: Field being validated. + :raises ValidationError: If the comparison field does not exist or both + fields contain equal values. + """ try: other = form[self.fieldname] except KeyError as exc: @@ -43,36 +54,67 @@ class NotEqualTo: or self.fieldname, "other_name": self.fieldname, } - message = self.message - if message is None: - message = field.gettext("Field must not be equal to %(other_name)s.") - + message = self.message or field.gettext( + "Field must not be equal to %(other_name)s." + ) raise ValidationError(message % d) class AllowedHostname: - def __init__(self, message=None): + """ + Validate that a URL uses an allowed hostname. + + :param message: Optional validation error message. + """ + + def __init__(self, message: str | None = None) -> None: + """ + Initialize the validator. + + :param message: Optional validation error message. + """ self.message = message - def __call__(self, form, field): + def __call__(self, form: BaseForm, field: Field) -> None: + """ + Validate that a URL uses an allowed hostname. + + :param form: Form containing the field. + :param field: Field containing the URL to validate. + :raises ValidationError: If the URL hostname is not configured as allowed. + """ if ( urlsplit(field.data).hostname in current_app.config["WEBMENTIONS_SSG_ALLOWED_HOSTNAMES"] ): return + raise ValidationError(self.message or field.gettext("Invalid input.")) - message = self.message - if self.message is None: - message = field.gettext("Invalid input.") - raise ValidationError(message) +class PublicURL: + """ + Validate that a URL resolves exclusively to public IP addresses. + :param message: Optional validation error message. + """ -class PublicURL: - def __init__(self, message=None): + def __init__(self, message: str | None = None) -> None: + """ + Initialize the validator. + + :param message: Optional validation error message. + """ self.message = message - def __call__(self, form, field): + def __call__(self, form: BaseForm, field: Field) -> None: + """ + Validate that a URL resolves exclusively to public IP addresses. + + :param form: Form containing the field. + :param field: Field containing the URL to validate. + :raises ValidationError: If the URL cannot be resolved, has no hostname, or + resolves to a non-public address. + """ message = self.message if message is None: |
