From 5b0ce6471ae5b15b0cd25841e3d2d57e01947cb0 Mon Sep 17 00:00:00 2001 From: Martin Zimmermann Date: Mon, 26 May 2014 18:47:49 +0200 Subject: [PATCH 1/3] add website input --- isso/js/app/i18n/en.js | 1 + isso/js/app/isso.js | 2 ++ isso/js/app/text/postbox.jade | 2 ++ isso/views/comments.py | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/isso/js/app/i18n/en.js b/isso/js/app/i18n/en.js index 6cc1d45..b29deab 100644 --- a/isso/js/app/i18n/en.js +++ b/isso/js/app/i18n/en.js @@ -2,6 +2,7 @@ define({ "postbox-text": "Type Comment Here (at least 3 chars)", "postbox-author": "Name (optional)", "postbox-email": "E-mail (optional)", + "postbox-website": "Website (optional)", "postbox-submit": "Submit", "num-comments": "One Comment\n{{ n }} Comments", diff --git a/isso/js/app/isso.js b/isso/js/app/isso.js index e3ca1b9..3a8fd96 100644 --- a/isso/js/app/isso.js +++ b/isso/js/app/isso.js @@ -64,11 +64,13 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n", api.create($("#isso-thread").getAttribute("data-isso-id"), { author: $("[name=author]", el).value || null, email: $("[name=email]", el).value || null, + website: $("[name=website]", el).value || null, text: utils.text($(".textarea", el).innerHTML), parent: parent || null }).then(function(comment) { $("[name=author]", el).value = ""; $("[name=email]", el).value = ""; + $("[name=website]", el).value = ""; $(".textarea", el).innerHTML = ""; $(".textarea", el).blur(); insert(comment, true); diff --git a/isso/js/app/text/postbox.jade b/isso/js/app/text/postbox.jade index 5740da0..5014c84 100644 --- a/isso/js/app/text/postbox.jade +++ b/isso/js/app/text/postbox.jade @@ -11,5 +11,7 @@ div(class='postbox') input(type='text' name='author' placeholder=i18n('postbox-author')) p(class='input-wrapper') input(type='email' name='email' placeholder=i18n('postbox-email')) + p(class='input-wrapper') + input(type='text' name='website' placeholder=i18n('postbox-website')) p(class='post-action') input(type='submit' value=i18n('postbox-submit')) diff --git a/isso/views/comments.py b/isso/views/comments.py index 207c5c0..cb2bfd6 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- +import re import cgi -import json import time import hashlib import functools @@ -22,6 +22,27 @@ from isso.utils import http, parse, JSONResponse as JSON from isso.utils.crypto import pbkdf2 from isso.views import requires +# from Django appearently, looks good to me *duck* +__url_re = re.compile( + r'^' + r'(https?://)?' + r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain... + r'localhost|' # localhost... + r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip + r'(?::\d+)?' # optional port + r'(?:/?|[/?]\S+)' + r'$', re.IGNORECASE) + + +def isurl(text): + return __url_re.match(text) is not None + + +def normalize(url): + if not url.startswith(("http://", "https://")): + return "http://" + url + return url + def sha1(text): return hashlib.sha1(text.encode('utf-8')).hexdigest() @@ -111,6 +132,12 @@ class API(object): if len(comment.get("email") or "") > 254: return False, "http://tools.ietf.org/html/rfc5321#section-4.5.3" + if comment.get("website"): + if len(comment["website"]) > 254: + return False, "arbitrary length limit" + if not isurl(comment["website"]): + return False, "Website not Django-conform" + return True, "" @xhr @@ -129,10 +156,13 @@ class API(object): if not valid: return BadRequest(reason) - for field in ("author", "email"): + for field in ("author", "email", "website"): if data.get(field) is not None: data[field] = cgi.escape(data[field]) + if data.get("website"): + data["website"] = normalize(data["website"]) + data['mode'] = 2 if self.moderated else 1 data['remote_addr'] = utils.anonymize(str(request.remote_addr)) From 065460d78a1fffde87c0dabf430c4551b21149df Mon Sep 17 00:00:00 2001 From: Martin Zimmermann Date: Tue, 27 May 2014 13:33:29 +0200 Subject: [PATCH 2/3] add tests for website validation --- isso/tests/test_comments.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/isso/tests/test_comments.py b/isso/tests/test_comments.py index 17a8b79..43d7ecf 100644 --- a/isso/tests/test_comments.py +++ b/isso/tests/test_comments.py @@ -129,8 +129,25 @@ class TestComments(unittest.TestCase): for text in ("", "\n\n\n"): self.assertFalse(verify({"text": text})) - # email length + # email/website length + self.assertTrue(verify({"text": "...", "email": "*"*254})) + self.assertTrue(verify({"text": "...", "website": "google.de/" + "a"*128})) + self.assertFalse(verify({"text": "...", "email": "*"*1024})) + self.assertFalse(verify({"text": "...", "website": "google.de/" + "*"*1024})) + + # valid website url + self.assertTrue(comments.isurl("example.tld")) + self.assertTrue(comments.isurl("http://example.tld")) + self.assertTrue(comments.isurl("https://example.tld")) + self.assertTrue(comments.isurl("https://example.tld:1337/")) + self.assertTrue(comments.isurl("https://example.tld:1337/foobar")) + self.assertTrue(comments.isurl("https://example.tld:1337/foobar?p=1#isso-thread")) + + self.assertFalse(comments.isurl("ftp://example.tld/")) + self.assertFalse(comments.isurl("tel:+1234567890")) + self.assertFalse(comments.isurl("+1234567890")) + self.assertFalse(comments.isurl("spam")) def testGetInvalid(self): From 77d40a99eb7bf7a28d28cfc34b13631d8d1c914a Mon Sep 17 00:00:00 2001 From: Martin Zimmermann Date: Tue, 27 May 2014 13:42:07 +0200 Subject: [PATCH 3/3] border-radius only for first and last input --- isso/css/isso.css | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/isso/css/isso.css b/isso/css/isso.css index d76c06f..827c145 100644 --- a/isso/css/isso.css +++ b/isso/css/isso.css @@ -182,12 +182,17 @@ .postbox > .form-wrapper > .auth-section .input-wrapper input { padding: .3em 10px; max-width: 100%; - border-radius: 3px; background-color: #fff; line-height: 1.4em; border: 1px solid rgba(0, 0, 0, 0.2); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } +.postbox > .form-wrapper > .auth-section .input-wrapper:first-child input { + border-radius: 3px 0 0 3px; +} +.postbox > .form-wrapper > .auth-section .input-wrapper:nth-last-child(2) input { + border-radius: 0 3px 3px 0; +} .postbox > .form-wrapper > .auth-section .post-action { display: inline-block; float: right; @@ -217,6 +222,7 @@ } .postbox > .form-wrapper > .auth-section .input-wrapper input { width: 100%; + border-radius: 3px; } .postbox > .form-wrapper > .auth-section .post-action { display: block;