forked from GithubBackups/healthchecks
Validate HTTP header names in the "Add Webhook" form.
This commit is contained in:
parent
6643a7771b
commit
55d6471156
@ -1,5 +1,6 @@
|
||||
import json
|
||||
from datetime import timedelta as td
|
||||
import json
|
||||
import re
|
||||
|
||||
from django import forms
|
||||
from django.core.validators import RegexValidator
|
||||
@ -55,28 +56,42 @@ class AddUrlForm(forms.Form):
|
||||
value = forms.URLField(max_length=1000, validators=[WebhookValidator()])
|
||||
|
||||
|
||||
_valid_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match
|
||||
|
||||
|
||||
class AddWebhookForm(forms.Form):
|
||||
error_css_class = "has-error"
|
||||
|
||||
url_down = forms.URLField(max_length=1000, required=False,
|
||||
validators=[WebhookValidator()])
|
||||
validators=[WebhookValidator()])
|
||||
|
||||
url_up = forms.URLField(max_length=1000, required=False,
|
||||
validators=[WebhookValidator()])
|
||||
validators=[WebhookValidator()])
|
||||
|
||||
post_data = forms.CharField(max_length=1000, required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AddWebhookForm, self).__init__(*args, **kwargs)
|
||||
|
||||
self.invalid_header_names = set()
|
||||
self.headers = {}
|
||||
if "header_key[]" in self.data and "header_value[]" in self.data:
|
||||
keys = self.data.getlist("header_key[]")
|
||||
values = self.data.getlist("header_value[]")
|
||||
for key, value in zip(keys, values):
|
||||
if key:
|
||||
self.headers[key] = value
|
||||
if not key:
|
||||
continue
|
||||
|
||||
if not _valid_header_name(key):
|
||||
self.invalid_header_names.add(key)
|
||||
|
||||
self.headers[key] = value
|
||||
|
||||
def clean(self):
|
||||
if self.invalid_header_names:
|
||||
raise forms.ValidationError("Invalid header names")
|
||||
|
||||
return self.cleaned_data
|
||||
|
||||
def get_value(self):
|
||||
val = dict(self.cleaned_data)
|
||||
|
@ -72,12 +72,27 @@ class AddWebhookTestCase(BaseTestCase):
|
||||
self.assertEqual(c.value, '{"headers": {}, "post_data": "hello", "url_down": "http://foo.com", "url_up": ""}')
|
||||
|
||||
def test_it_adds_headers(self):
|
||||
form = {"url_down": "http://foo.com", "header_key[]": ["test", "test2"], "header_value[]": ["123", "abc"]}
|
||||
form = {
|
||||
"url_down": "http://foo.com",
|
||||
"header_key[]": ["test", "test2"],
|
||||
"header_value[]": ["123", "abc"]
|
||||
}
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post(self.url, form)
|
||||
self.assertRedirects(r, "/integrations/")
|
||||
|
||||
c = Channel.objects.get()
|
||||
self.assertEqual(c.value, '{"headers": {"test": "123", "test2": "abc"}, "post_data": "", "url_down": "http://foo.com", "url_up": ""}')
|
||||
self.assertEqual(c.headers, {"test": "123", "test2": "abc"})
|
||||
|
||||
def test_it_rejects_bad_header_names(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
form = {
|
||||
"url_down": "http://example.org",
|
||||
"header_key[]": ["ill:egal"],
|
||||
"header_value[]": ["123"]
|
||||
}
|
||||
|
||||
r = self.client.post(self.url, form)
|
||||
self.assertContains(r, "Please use valid HTTP header names.")
|
||||
self.assertEqual(Channel.objects.count(), 0)
|
||||
|
4
static/css/add_webhook.css
Normal file
4
static/css/add_webhook.css
Normal file
@ -0,0 +1,4 @@
|
||||
.webhook-header .error {
|
||||
border-color: #a94442;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
<link rel="stylesheet" href="{% static 'css/channel_checks.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/log.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/add_pushover.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/add_webhook.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/settings.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/last_ping.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/profile.css' %}" type="text/css">
|
||||
|
@ -105,32 +105,36 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group {{ form.headers.css_classes }}">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">Request Headers</label>
|
||||
<div id="webhook-headers" class="col-xs-12 col-sm-10">
|
||||
{% for k, v in form.headers.items %}
|
||||
<div class="form-inline webhook-header">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control key"
|
||||
name="header_key[]"
|
||||
placeholder="Content-Type"
|
||||
value="{{ k }}" />
|
||||
<input
|
||||
type="text"
|
||||
class="form-control value"
|
||||
name="header_value[]"
|
||||
placeholder="application/json"
|
||||
value="{{ v }}" />
|
||||
<button class="btn btn-default" type="button">
|
||||
<span class="icon-delete"></span>
|
||||
</button>
|
||||
<div class="col-xs-12 col-sm-10">
|
||||
<div id="webhook-headers">
|
||||
{% for k, v in form.headers.items %}
|
||||
<div class="form-inline webhook-header">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control key {% if k in form.invalid_header_names %}error{% endif %}"
|
||||
name="header_key[]"
|
||||
placeholder="Content-Type"
|
||||
value="{{ k }}" />
|
||||
<input
|
||||
type="text"
|
||||
class="form-control value"
|
||||
name="header_value[]"
|
||||
placeholder="application/json"
|
||||
value="{{ v }}" />
|
||||
<button class="btn btn-default" type="button">
|
||||
<span class="icon-delete"></span>
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if form.invalid_header_names %}
|
||||
<div class="text-danger">
|
||||
Please use valid HTTP header names.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-center">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
|
Loading…
x
Reference in New Issue
Block a user