← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands-website/inquiry_spam into lp:widelands-website

 

kaputtnik has proposed merging lp:~widelands-dev/widelands-website/inquiry_spam into lp:widelands-website.

Commit message:
Add a simple spam filter to legal_notice checking for ALLOWED_INQUIRY_HOSTS

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1799375 in Widelands Website: "Stop spam coming over legal_notice"
  https://bugs.launchpad.net/widelands-website/+bug/1799375

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands-website/inquiry_spam/+merge/361998

Mails sent through legal_notice will be prevented if the inquiry contain links to elsewhere, except the ones defined by ALLOWED_INQUIRY_HOSTS. If such a link is found, an errormessage is shown to the user. Additionally the status code Http 400 "Bad request" is send, which hopefully get recognized by spambots. Not sure though if sending Http 400 is a good approach.

This should prevent round about 95% of the spam mails coming from legal_notice.


-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands-website/inquiry_spam into lp:widelands-website.
=== modified file 'mainpage/forms.py'
--- mainpage/forms.py	2018-09-04 18:17:07 +0000
+++ mainpage/forms.py	2019-01-19 15:23:47 +0000
@@ -2,13 +2,14 @@
 # encoding: utf-8
 
 from django import forms
+from django.conf import settings
 from registration.forms import RegistrationForm
 from nocaptcha_recaptcha.fields import NoReCaptchaField
 from wlprofile.models import Profile as wlprofile
+from pybb.util import PLAIN_LINK_RE
+
 
 # Overwritten form to include a captcha
-
-
 class RegistrationWithCaptchaForm(RegistrationForm):
     captcha = NoReCaptchaField()
 
@@ -16,5 +17,24 @@
 class ContactForm(forms.Form):
     surname = forms.CharField(max_length=80, required=False)
     forename = forms.CharField(max_length=80, required=False)
-    email = forms.EmailField()
-    inquiry = forms.CharField(widget=forms.Textarea)
+    email = forms.EmailField(initial='')
+    inquiry = forms.CharField(widget=forms.Textarea, initial='')
+
+    def clean_inquiry(self):
+        # A simple Spam filter looking for urls
+        given_links = PLAIN_LINK_RE.findall(self.cleaned_data['inquiry'])
+        for link in given_links:
+            for host in settings.ALLOWED_INQUIRY_HOSTS:
+                valid_link = host in link  # True, else: False
+                if valid_link:
+                    # Found host in link, continue with the first loop
+                    break
+            if not valid_link:
+                # If we get here, at least one of the given links haven't an
+                # allowed host
+                raise forms.ValidationError(
+                    'Not accepted URL in inquiry')
+
+        # Always return a value, even if
+        # this method didn't change it.
+        return self.cleaned_data['inquiry']

=== modified file 'mainpage/views.py'
--- mainpage/views.py	2018-11-08 20:11:19 +0000
+++ mainpage/views.py	2019-01-19 15:23:47 +0000
@@ -1,4 +1,4 @@
-from settings import WIDELANDS_SVN_DIR, INQUIRY_RECIPIENTS
+from django.conf import settings
 from templatetags.wl_markdown import do_wl_markdown
 from operator import itemgetter
 from django.core.mail import send_mail
@@ -21,6 +21,7 @@
     """The legal notice page to fullfill law."""
     if request.method == 'POST':
         form = ContactForm(request.POST)
+        
         if form.is_valid():
             name = form.cleaned_data['forename'] + \
                 ' ' + form.cleaned_data['surname']
@@ -32,22 +33,35 @@
             sender = 'legal_note@xxxxxxxxxxxxx'
 
             # get email addresses which are in form of ('name','email'),
-            recipients = []
-            for recipient in INQUIRY_RECIPIENTS:
-                recipients.append(recipient[1])
+            recipients = [ x[1] for x in settings.ADMINS ]
 
             send_mail(subject, message, sender,
                       recipients, fail_silently=False)
+
             # Redirect after POST
             return HttpResponseRedirect('/legal_notice_thanks/')
-
+        else:
+            # Form errors, return the form with values
+            return render(
+                request,
+                'mainpage/legal_notice.html',
+                {
+                    'form': form,
+                    'inquiry_recipients': settings.ADMINS,
+                },
+                status=400, # Return Http400 'Bad request'
+                )
     else:
         form = ContactForm()  # An unbound form
 
-    return render(request, 'mainpage/legal_notice.html', {
-        'form': form,
-        'inquiry_recipients': INQUIRY_RECIPIENTS,
-    })
+    return render(
+        request,
+        'mainpage/legal_notice.html',
+        {
+            'form': form,
+            'inquiry_recipients': settings.ADMINS,
+        }
+        )
 
 
 def legal_notice_thanks(request):
@@ -67,7 +81,7 @@
     txt = '[TOC]\n\n'
     transl_files = []
     transl_list = []
-    path = os.path.normpath(WIDELANDS_SVN_DIR + 'data/i18n/locales/')
+    path = os.path.normpath(settings.WIDELANDS_SVN_DIR + 'data/i18n/locales/')
     try:
         transl_files = os.listdir(path)
         if transl_files:
@@ -100,7 +114,7 @@
     # Get other developers, put in the translators list
     # at given position and prepare all for wl_markdown
     try:
-        with open(WIDELANDS_SVN_DIR + 'data/txts/developers.json', 'r') as f:
+        with open(settings.WIDELANDS_SVN_DIR + 'data/txts/developers.json', 'r') as f:
             json_data = json.load(f)['developers']
 
         for head in json_data:
@@ -140,7 +154,7 @@
     This replaces the wiki changelog
 
     """
-    data = codecs.open(WIDELANDS_SVN_DIR + 'ChangeLog', encoding='utf-8', mode='r').read()
+    data = codecs.open(settings.WIDELANDS_SVN_DIR + 'ChangeLog', encoding='utf-8', mode='r').read()
     return render(request, 'mainpage/changelog.html',
                   {'changelog': data},
                   )

=== modified file 'settings.py'
--- settings.py	2018-12-18 11:38:34 +0000
+++ settings.py	2019-01-19 15:23:47 +0000
@@ -6,9 +6,15 @@
 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
 DEBUG = True
 
-ADMINS = (
+###############################################
+# Recipient(s) who get an email if something  #
+# goes wrong on the site. Also used as        #
+# recipients in the form on legal notice page #
+###############################################
+
+ADMINS = [
     # ('Your Name', 'your_email@xxxxxxxxxx'),
-)
+]
 
 MANAGERS = ADMINS
 
@@ -276,15 +282,6 @@
 ########
 MAPS_PER_PAGE = 10
 
-##############################################
-## Recipient(s) who get an email if someone ##
-## uses the form on legal notice page       ##
-## Use allways the form ('name', 'Email')   ##
-##############################################
-INQUIRY_RECIPIENTS = [
-    ('peter', 'peter@xxxxxxxxxxx'),
-]
-
 ##########################################
 ## Allowed tags/attributes for 'bleach' ##
 ## Used for sanitizing user input.      ##
@@ -346,6 +343,16 @@
 STAR_RATINGS_STAR_WIDTH = 14
 STAR_RATINGS_RANGE = 10
 
+####################
+# Inquiry settings #
+####################
+
+ALLOWED_INQUIRY_HOSTS = [
+    '.launchpad.net/',
+    'https://wl.widelands.org/',
+    'https://github.com/',
+    ]
+
 try:
     from local_settings import *
 except ImportError:

=== modified file 'templates/mainpage/legal_notice.html'
--- templates/mainpage/legal_notice.html	2018-10-14 13:24:15 +0000
+++ templates/mainpage/legal_notice.html	2019-01-19 15:23:47 +0000
@@ -21,7 +21,6 @@
    <p>There are several possibilities to get in contact. For questions about the game or the contents of the website please take a look at our <a href=/wiki/ContactPage>Contact page</a> or post in the <a href=/forum>forums</a>. Use the one of the following methods if you do not want to make an account:</p>
 
 	<ul>
-	<li>E-Mail Holger Rapp: sirver(at)gmx.de</li>
 	<li>Contact form. Using this form sends E-Mails to following person(s):
     <ul>
         {% for name, recipient in inquiry_recipients %}
@@ -37,22 +36,25 @@
 		</tr>
 		<tr>
 			<td><label for="id_surname">Last name (optional): </label></td>
-			<td><input id="id_surname" type="text" name="surname" maxlength="80"></td>
+			<td><input id="id_surname" name="surname" maxlength="80" ></td>
 		</tr>
 		<tr>
 			<td><label for="id_email">Email:</label></td>
-			<td><input type="email" name="email" id="id_email" required>
+			<td>
 				{% for error in form.email.errors %}
-					<span class="errormessage">{{ error }}</span>
+					<span class="errormessage">{{ error }}</span><br />
 				{% endfor %}
+				<input type="email" name="email" id="id_email" value="{{ form.email.value }}" required>
 			</td>
 		</tr>
 		<tr>
-			<td><label for="id_inquiry">Inquiry: </label>{{ form.inquiry.errors }}</td>
-			<td><textarea id="id_inquiry" rows="10" cols="40" name="inquiry" required></textarea>
+			<td><label for="id_inquiry">Inquiry: </label></td>
+			<td>
 				{% for error in form.inquiry.errors %}
-					<span class="errormessage">{{ error }}</span>
+					<span class="errormessage">{{ error }}</span><br />
 				{% endfor %}
+				{# Keep in one line, otherwise tabs will be inserted #}
+				<textarea id="id_inquiry" rows="10" cols="40" name="inquiry" required>{{ form.inquiry.value }}</textarea>
 			</td>
 		</tr>
 		<tr>


Follow ups