diff --git a/requirements.txt b/requirements.txt index 8501843c..993c3787 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,3 +34,4 @@ lxml==3.5.0 git+https://github.com/Xof/django-pglocks.git@dbb8d7375066859f897604132bd437832d2014ea pyjwkest==1.0.9 python-dateutil==2.4.2 +netaddr==0.7.18 diff --git a/settings/common.py b/settings/common.py index 13e5ae4b..de8bc628 100644 --- a/settings/common.py +++ b/settings/common.py @@ -508,7 +508,8 @@ PROJECT_MODULES_CONFIGURATORS = { "bitbucket": "taiga.hooks.bitbucket.services.get_or_generate_config", } -BITBUCKET_VALID_ORIGIN_IPS = ["131.103.20.165", "131.103.20.166"] +BITBUCKET_VALID_ORIGIN_IPS = ["131.103.20.165", "131.103.20.166", "104.192.143.192/28", "104.192.143.208/28"] + GITLAB_VALID_ORIGIN_IPS = [] EXPORTS_TTL = 60 * 60 * 24 # 24 hours diff --git a/taiga/hooks/bitbucket/api.py b/taiga/hooks/bitbucket/api.py index ee1ffd5b..afd3c47b 100644 --- a/taiga/hooks/bitbucket/api.py +++ b/taiga/hooks/bitbucket/api.py @@ -24,6 +24,7 @@ from taiga.hooks.api import BaseWebhookApiViewSet from . import event_hooks +from netaddr import all_matching_cidrs from urllib.parse import parse_qs from ipware.ip import get_ip @@ -55,7 +56,7 @@ class BitBucketViewSet(BaseWebhookApiViewSet): valid_origin_ips = bitbucket_config.get("valid_origin_ips", settings.BITBUCKET_VALID_ORIGIN_IPS) origin_ip = get_ip(request) - if valid_origin_ips and (not origin_ip or origin_ip not in valid_origin_ips): + if valid_origin_ips and (len(all_matching_cidrs(origin_ip,valid_origin_ips)) == 0): return False return project_secret == secret_key diff --git a/taiga/hooks/gitlab/api.py b/taiga/hooks/gitlab/api.py index 66c4a58e..89f6a5c8 100644 --- a/taiga/hooks/gitlab/api.py +++ b/taiga/hooks/gitlab/api.py @@ -26,6 +26,7 @@ from taiga.hooks.api import BaseWebhookApiViewSet from . import event_hooks +from netaddr import all_matching_cidrs class GitLabViewSet(BaseWebhookApiViewSet): event_hook_classes = { @@ -53,7 +54,8 @@ class GitLabViewSet(BaseWebhookApiViewSet): gitlab_config = project.modules_config.config.get("gitlab", {}) valid_origin_ips = gitlab_config.get("valid_origin_ips", settings.GITLAB_VALID_ORIGIN_IPS) origin_ip = get_ip(request) - if valid_origin_ips and (not origin_ip or origin_ip not in valid_origin_ips): + + if valid_origin_ips and (len(all_matching_cidrs(origin_ip,valid_origin_ips)) == 0): return False return project_secret == secret_key diff --git a/tests/integration/test_hooks_bitbucket.py b/tests/integration/test_hooks_bitbucket.py index bef9330f..c21ca332 100644 --- a/tests/integration/test_hooks_bitbucket.py +++ b/tests/integration/test_hooks_bitbucket.py @@ -61,6 +61,25 @@ def test_ok_signature(client): assert response.status_code == 204 +def test_ok_signature_ip_in_network(client): + project = f.ProjectFactory() + f.ProjectModulesConfigFactory(project=project, config={ + "bitbucket": { + "secret": "tpnIwJDz4e" + } + }) + + url = reverse("bitbucket-hook-list") + url = "{}?project={}&key={}".format(url, project.id, "tpnIwJDz4e") + data = json.dumps({"push": {"changes": [{"new": {"target": { "message": "test message"}}}]}}) + response = client.post(url, + data, + content_type="application/json", + HTTP_X_EVENT_KEY="repo:push", + REMOTE_ADDR="104.192.143.193") + assert response.status_code == 204 + + def test_invalid_ip(client): project = f.ProjectFactory() f.ProjectModulesConfigFactory(project=project, config={ diff --git a/tests/integration/test_hooks_gitlab.py b/tests/integration/test_hooks_gitlab.py index 7264b2c1..cd0c2b8b 100644 --- a/tests/integration/test_hooks_gitlab.py +++ b/tests/integration/test_hooks_gitlab.py @@ -59,6 +59,26 @@ def test_ok_signature(client): assert response.status_code == 204 +def test_ok_signature_ip_in_network(client): + project = f.ProjectFactory() + f.ProjectModulesConfigFactory(project=project, config={ + "gitlab": { + "secret": "tpnIwJDz4e", + "valid_origin_ips": ["111.111.111.0/24"], + } + }) + + url = reverse("gitlab-hook-list") + url = "{}?project={}&key={}".format(url, project.id, "tpnIwJDz4e") + data = {"test:": "data"} + response = client.post(url, + json.dumps(data), + content_type="application/json", + REMOTE_ADDR="111.111.111.112") + + assert response.status_code == 204 + + def test_invalid_ip(client): project = f.ProjectFactory() f.ProjectModulesConfigFactory(project=project, config={