diff --git a/app/Http/Controllers/MailController.php b/app/Http/Controllers/MailController.php index eb7d9c1f3a5d50458dbfb84cf55b57b6d333bc13..9ff957dede09aec132a570cfdd8f5b6ee108e70f 100644 --- a/app/Http/Controllers/MailController.php +++ b/app/Http/Controllers/MailController.php @@ -30,9 +30,11 @@ class MailController extends Controller $validator = Validator::make( [ 'email' => $request->input('email'), + 'pcsrf' => $request->input('pcsrf'), ], [ 'email' => 'required|email', + 'pcsrf' => ['required', 'string', new \App\Rules\PCSRF], ] ); diff --git a/app/Rules/PCSRF.php b/app/Rules/PCSRF.php new file mode 100644 index 0000000000000000000000000000000000000000..6e9f9110a7dd5fe2ce7fabb5284b5b9e4318fccb --- /dev/null +++ b/app/Rules/PCSRF.php @@ -0,0 +1,64 @@ +<?php + +namespace App\Rules; + +use Illuminate\Contracts\Validation\Rule; + +class PCSRF implements Rule +{ + /** + * Create a new rule instance. + * + * @return void + */ + public function __construct() + { + // + } + + /** + * Determine if the validation rule passes. + * + * @param string $attribute + * @param mixed $value + * @return bool + */ + public function passes($attribute, $value) + { + // Nobody wants to fight through hundreds of mails every day regarding + // oranges or 60m rinse hoses + // However CSRF requires some sort of user session which we want to avoid + // That's why we implement a similar but easier to bypass method of pseudo CSRF + + // $value should contain a base64 encoded timestamp + if (base64_encode(base64_decode($value, true)) !== $value) { + return false; + } else { + $value = base64_decode($value, true); + } + if (\is_int($value)) { + return false; + } else { + $value = intval($value); + } + + $currentTime = \time(); + + // If the request was sent faster than 5 seconds or if it took longer than one hour we assume it's spam + if (($currentTime - 5) <= $value || ($currentTime - 3600) >= $value) { + return false; + } + + return true; + } + + /** + * Get the validation error message. + * + * @return string + */ + public function message() + { + return trans("validation.pcsrf"); + } +} diff --git a/resources/lang/de/validation.php b/resources/lang/de/validation.php index 69a0e99c457e5ed1b2b551af7fb5ab72ce0c7418..5282e40a980cbf315af9448cfe101822f7d0b641 100644 --- a/resources/lang/de/validation.php +++ b/resources/lang/de/validation.php @@ -1,79 +1,80 @@ <?php return [ - "accepted" => "Das Feld :attribute muss akzeptiert werden.", - "active_url" => "Das Feld :attribute ist keine richtige URL.", - "after" => "Das Feld :attribute muss ein Datum nach :date sein.", - "alpha" => "Das Feld :attribute darf nur Buchstaben enthalten.", - "alpha_dash" => "Das Feld :attribute darf nur Buchstaben, Zahlen und Gedankenstriche enthalten.", - "alpha_num" => "Das Feld :attribute darf nur Buchstaben und Zahlen enthalten.", - "array" => "Das Feld :attribute muss ein Array sein.", - "before" => "Das Feld :attribute muss ein Datum vor :date sein.", - "between" => [ - "numeric" => "Das Feld :attribute muss zwischen :min und :max liegen.", - "file" => "Die Datei :attribute muss zwischen :min und :max Kilobyte groß sein.", - "string" => "Das Feld :attribute muss zwischen :min und :max Zeichen haben.", - "array" => "Das Array :attribute muss zwischen :min und :max Elemente haben." + "accepted" => "Das Feld :attribute muss akzeptiert werden.", + "active_url" => "Das Feld :attribute ist keine richtige URL.", + "after" => "Das Feld :attribute muss ein Datum nach :date sein.", + "alpha" => "Das Feld :attribute darf nur Buchstaben enthalten.", + "alpha_dash" => "Das Feld :attribute darf nur Buchstaben, Zahlen und Gedankenstriche enthalten.", + "alpha_num" => "Das Feld :attribute darf nur Buchstaben und Zahlen enthalten.", + "array" => "Das Feld :attribute muss ein Array sein.", + "before" => "Das Feld :attribute muss ein Datum vor :date sein.", + "between" => [ + "numeric" => "Das Feld :attribute muss zwischen :min und :max liegen.", + "file" => "Die Datei :attribute muss zwischen :min und :max Kilobyte groß sein.", + "string" => "Das Feld :attribute muss zwischen :min und :max Zeichen haben.", + "array" => "Das Array :attribute muss zwischen :min und :max Elemente haben.", ], - "boolean" => "Das Feld :attribute muss entweder \"true\", oder \"false\" sein.", - "confirmed" => "Die Bestätigung des Feldes :attribute stimmt nicht überein.", - "date" => "Das Feld :attribute ist kein korrektes Datum.", - "date_format" => "Das Feld :attribute stimmt nicht mit dem Format :format überein.", - "different" => "Das Feld :attribute und :other müssen unterschiedlich sein.", - "digits" => "Das Feld :attribute muss :digits Ziffern enthalten.", - "digits_between" => "Das Feld :attribute muss zwischen :min und :max Ziffern enthalten.", - "distinct" => "Das Feld :attribute kommt doppelt vor.", - "email" => "Das Feld :attribute muss eine korrekte Email-Adresse sein.", - "exists" => "Das gewählte Feld :attribute existiert nicht.", - "filled" => "Das Feld :attribute wird benötigt.", - "image" => "Das Feld :attribute muss ein gültiges Bild sein.", - "in" => "Das gewählte Feld :attribute existiert nicht.", - "in_array" => "Das Feld :attribute existiert nicht in :other.", - "integer" => "Das Feld :attribute muss ein Integer sein.", - "ip" => "Das Feld :attribute muss eine gültige IP Adresse sein.", - "json" => "Das Feld :attribute muss ein gültiger JSON String sein.", - "max" => [ - "numeric" => "Das Feld :attribute darf nicht größer sein als :max.", - "file" => "Das Feld :attribute darf nicht größer sein als :max Kilobyte", - "string" => "Das Feld :attribute darf nicht mehr als :max Zeichen enthalten.", - "array" => "Das Feld :attribute darf nicht mehr als :max Elemente enthalten." + "boolean" => "Das Feld :attribute muss entweder \"true\", oder \"false\" sein.", + "confirmed" => "Die Bestätigung des Feldes :attribute stimmt nicht überein.", + "date" => "Das Feld :attribute ist kein korrektes Datum.", + "date_format" => "Das Feld :attribute stimmt nicht mit dem Format :format überein.", + "different" => "Das Feld :attribute und :other müssen unterschiedlich sein.", + "digits" => "Das Feld :attribute muss :digits Ziffern enthalten.", + "digits_between" => "Das Feld :attribute muss zwischen :min und :max Ziffern enthalten.", + "distinct" => "Das Feld :attribute kommt doppelt vor.", + "email" => "Das Feld :attribute muss eine korrekte Email-Adresse sein.", + "exists" => "Das gewählte Feld :attribute existiert nicht.", + "filled" => "Das Feld :attribute wird benötigt.", + "image" => "Das Feld :attribute muss ein gültiges Bild sein.", + "in" => "Das gewählte Feld :attribute existiert nicht.", + "in_array" => "Das Feld :attribute existiert nicht in :other.", + "integer" => "Das Feld :attribute muss ein Integer sein.", + "ip" => "Das Feld :attribute muss eine gültige IP Adresse sein.", + "json" => "Das Feld :attribute muss ein gültiger JSON String sein.", + "max" => [ + "numeric" => "Das Feld :attribute darf nicht größer sein als :max.", + "file" => "Das Feld :attribute darf nicht größer sein als :max Kilobyte", + "string" => "Das Feld :attribute darf nicht mehr als :max Zeichen enthalten.", + "array" => "Das Feld :attribute darf nicht mehr als :max Elemente enthalten.", ], - "mimes" => "Das Feld :attribute muss eine Datei vom Typ: :values sein.", - "min" => [ - "numeric" => "Die Zahl :attribute muss mindestens :min sein.", - "file" => "Die Datei :attribute muss midnestens :min Kilobyte groß sein.", - "string" => "Der Text :attribute muss mindestens :min Zeichen enthalten.", - "array" => "das Array :attribute muss mindestens :min Elemente enthalten." + "mimes" => "Das Feld :attribute muss eine Datei vom Typ: :values sein.", + "min" => [ + "numeric" => "Die Zahl :attribute muss mindestens :min sein.", + "file" => "Die Datei :attribute muss midnestens :min Kilobyte groß sein.", + "string" => "Der Text :attribute muss mindestens :min Zeichen enthalten.", + "array" => "das Array :attribute muss mindestens :min Elemente enthalten.", ], - "not_in" => "Das gewählte Feld :attribute is nicht vorhanden.", - "numeric" => "Das Feld :attribute muss eine Zahl sein.", - "present" => "Das Feld :attribute muss angegeben werden.", - "regex" => "Das Feld :attribute hat ein ungültiges format.", - "required" => "Das Feld :attribute wird benötigt.", - "required_if" => "Das Feld :attribute wird benötigt, wenn :other :value ist.", - "required_unless" => "Das Feld :attribute wird benötigt wenn :other in :values vorhanden ist.", - "required_with" => "Das Feld :attribute wird benötigt, wenn :values angegeben wurde.", - "required_with_all" => "Das Feld :attribute wird benötigt, wenn :values angegeben wurden.", - "required_without" => "Das Feld :attribute wird benötigt, wenn :values nicht angegeben wurde.", - "required_without_all" => "Das Feld :attribute wird benötigt, wenn keins der folgenden angegeben wurde: :values.", - "same" => "Das Feld :attribute und :other müssen übereinstimmten.", - "size" => [ - "numeric" => "Das Feld :attribute muss mindestens :size sein.", - "file" => "Das Feld :attribute muss mindestens :size Kilobyte groß sein.", - "string" => "Das Feld :attribute muss mindestens :size Zeichen lang sein.", - "array" => "Das Feld :attribute muss mindestens :size Elemente enthalten." + "not_in" => "Das gewählte Feld :attribute is nicht vorhanden.", + "numeric" => "Das Feld :attribute muss eine Zahl sein.", + "present" => "Das Feld :attribute muss angegeben werden.", + "regex" => "Das Feld :attribute hat ein ungültiges format.", + "required" => "Das Feld :attribute wird benötigt.", + "required_if" => "Das Feld :attribute wird benötigt, wenn :other :value ist.", + "required_unless" => "Das Feld :attribute wird benötigt wenn :other in :values vorhanden ist.", + "required_with" => "Das Feld :attribute wird benötigt, wenn :values angegeben wurde.", + "required_with_all" => "Das Feld :attribute wird benötigt, wenn :values angegeben wurden.", + "required_without" => "Das Feld :attribute wird benötigt, wenn :values nicht angegeben wurde.", + "required_without_all" => "Das Feld :attribute wird benötigt, wenn keins der folgenden angegeben wurde: :values.", + "same" => "Das Feld :attribute und :other müssen übereinstimmten.", + "size" => [ + "numeric" => "Das Feld :attribute muss mindestens :size sein.", + "file" => "Das Feld :attribute muss mindestens :size Kilobyte groß sein.", + "string" => "Das Feld :attribute muss mindestens :size Zeichen lang sein.", + "array" => "Das Feld :attribute muss mindestens :size Elemente enthalten.", ], - "string" => "Das Feld :attribute muss ein String sein.", - "timezone" => "Das Feld :attribute muss eine gültige Zeitzone sein.", - "unique" => "Das Feld :attribute wurde schon verwendet.", - "url" => "Das Feld :attribute hat ein ungültiges Format.", - "custom" => [ - "attribute-name" => [ - "rule-name" => "eigene-nachricht" - ] + "string" => "Das Feld :attribute muss ein String sein.", + "timezone" => "Das Feld :attribute muss eine gültige Zeitzone sein.", + "unique" => "Das Feld :attribute wurde schon verwendet.", + "url" => "Das Feld :attribute hat ein ungültiges Format.", + "custom" => [ + "attribute-name" => [ + "rule-name" => "eigene-nachricht", + ], ], - "dimensions" => ":attribute hat die falsche Größe.", - "file" => "Das Feld :attribute muss eine Datei sein.", - "mimetypes" => "Das Feld :attribute muss eine Datei vom Typ :values sein.", - "uploaded" => ":attribute konnte nicht hochgeladen werden." -]; \ No newline at end of file + "dimensions" => ":attribute hat die falsche Größe.", + "file" => "Das Feld :attribute muss eine Datei sein.", + "mimetypes" => "Das Feld :attribute muss eine Datei vom Typ :values sein.", + "uploaded" => ":attribute konnte nicht hochgeladen werden.", + "pcsrf" => "Das hat leider nicht geklappt. Bitte versuchen Sie es noch einmal.", +]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 73b49d084d21f47bee8e4b1e896f593d93226d5e..aa51dec0ad4bb3c40609b59041c7b310b2a7df49 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -11,78 +11,78 @@ return [ | the validator class. Some of these rules have multiple versions such | as the size rules. Feel free to tweak each of these messages here. | - */ + */ - 'accepted' => 'The :attribute must be accepted.', - 'active_url' => 'The :attribute is not a valid URL.', - 'after' => 'The :attribute must be a date after :date.', - 'alpha' => 'The :attribute may only contain letters.', - 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', - 'alpha_num' => 'The :attribute may only contain letters and numbers.', - 'array' => 'The :attribute must be an array.', - 'before' => 'The :attribute must be a date before :date.', - 'between' => [ + 'accepted' => 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ 'numeric' => 'The :attribute must be between :min and :max.', - 'file' => 'The :attribute must be between :min and :max kilobytes.', - 'string' => 'The :attribute must be between :min and :max characters.', - 'array' => 'The :attribute must have between :min and :max items.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', ], - 'boolean' => 'The :attribute field must be true or false.', - 'confirmed' => 'The :attribute confirmation does not match.', - 'date' => 'The :attribute is not a valid date.', - 'date_format' => 'The :attribute does not match the format :format.', - 'different' => 'The :attribute and :other must be different.', - 'digits' => 'The :attribute must be :digits digits.', - 'digits_between' => 'The :attribute must be between :min and :max digits.', - 'dimensions' => 'The :attribute has invalid image dimensions.', - 'distinct' => 'The :attribute field has a duplicate value.', - 'email' => 'The :attribute must be a valid email address.', - 'exists' => 'The selected :attribute is invalid.', - 'file' => 'The :attribute must be a file.', - 'filled' => 'The :attribute field is required.', - 'image' => 'The :attribute must be an image.', - 'in' => 'The selected :attribute is invalid.', - 'in_array' => 'The :attribute field does not exist in :other.', - 'integer' => 'The :attribute must be an integer.', - 'ip' => 'The :attribute must be a valid IP address.', - 'json' => 'The :attribute must be a valid JSON string.', - 'max' => [ + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'dimensions' => 'The :attribute has invalid image dimensions.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'file' => 'The :attribute must be a file.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ 'numeric' => 'The :attribute may not be greater than :max.', - 'file' => 'The :attribute may not be greater than :max kilobytes.', - 'string' => 'The :attribute may not be greater than :max characters.', - 'array' => 'The :attribute may not have more than :max items.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', ], - 'mimes' => 'The :attribute must be a file of type: :values.', - 'mimetypes' => 'The :attribute must be a file of type: :values.', - 'min' => [ + 'mimes' => 'The :attribute must be a file of type: :values.', + 'mimetypes' => 'The :attribute must be a file of type: :values.', + 'min' => [ 'numeric' => 'The :attribute must be at least :min.', - 'file' => 'The :attribute must be at least :min kilobytes.', - 'string' => 'The :attribute must be at least :min characters.', - 'array' => 'The :attribute must have at least :min items.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', ], - 'not_in' => 'The selected :attribute is invalid.', - 'numeric' => 'The :attribute must be a number.', - 'present' => 'The :attribute field must be present.', - 'regex' => 'The :attribute format is invalid.', - 'required' => 'The :attribute field is required.', - 'required_if' => 'The :attribute field is required when :other is :value.', - 'required_unless' => 'The :attribute field is required unless :other is in :values.', - 'required_with' => 'The :attribute field is required when :values is present.', - 'required_with_all' => 'The :attribute field is required when :values is present.', - 'required_without' => 'The :attribute field is required when :values is not present.', + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', 'required_without_all' => 'The :attribute field is required when none of :values are present.', - 'same' => 'The :attribute and :other must match.', - 'size' => [ + 'same' => 'The :attribute and :other must match.', + 'size' => [ 'numeric' => 'The :attribute must be :size.', - 'file' => 'The :attribute must be :size kilobytes.', - 'string' => 'The :attribute must be :size characters.', - 'array' => 'The :attribute must contain :size items.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', ], - 'string' => 'The :attribute must be a string.', - 'timezone' => 'The :attribute must be a valid zone.', - 'unique' => 'The :attribute has already been taken.', - 'uploaded' => 'The :attribute failed to upload.', - 'url' => 'The :attribute format is invalid.', + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'uploaded' => 'The :attribute failed to upload.', + 'url' => 'The :attribute format is invalid.', /* |-------------------------------------------------------------------------- @@ -93,7 +93,7 @@ return [ | convention "attribute.rule" to name the lines. This makes it quick to | specify a specific custom language line for a given attribute rule. | - */ + */ 'custom' => [ 'attribute-name' => [ @@ -110,8 +110,8 @@ return [ | with something more reader friendly such as E-Mail Address instead | of "email". This simply helps us make messages a little cleaner. | - */ + */ 'attributes' => [], - + "pcsrf" => "Unfortunately this did not work. Please try again.", ]; diff --git a/resources/views/kontakt/kontakt.blade.php b/resources/views/kontakt/kontakt.blade.php index b12d7d37745d73cc9ab63a4dd43f63b867a9d02c..f7aed2ec917620a875a274a37973c3ae0946dc86 100644 --- a/resources/views/kontakt/kontakt.blade.php +++ b/resources/views/kontakt/kontakt.blade.php @@ -15,6 +15,7 @@ @endif <form class="contact" name="contact" method="post" action="{{ LaravelLocalization::getLocalizedURL(LaravelLocalization::getCurrentLocale(), "/kontakt") }}"> {{ csrf_field() }} + <input type="hidden" name="pcsrf" value="{{ base64_encode(\time()) }}"> <div class="form-group kontakt-form-group"> <input class="form-control" name="name" placeholder="{!!trans('kontakt.form.name')!!}" type="text" required @if(isset($formerrors) && Request::has('name'))value="{{Request::input('name')}}"@endif> </div>