From 9e830d1df8de2cf22fd78e47601e584465d268f5 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Chibon <pingou@pingoured.fr>
Date: Apr 19 2018 10:07:18 +0000
Subject: Insert CORS headers if some are configured


Fixes https://pagure.io/waiverdb/issue/160

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

Signed-off-by: Pierre-Yves Chibon <pingou@pingoured.fr>

---

diff --git a/tests/conftest.py b/tests/conftest.py
index b058202..69753f9 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -70,3 +70,8 @@ def enable_kerberos(app, monkeypatch):
 @pytest.fixture()
 def enable_ssl(app, monkeypatch):
     monkeypatch.setitem(app.config, 'AUTH_METHOD', 'SSL')
+
+
+@pytest.fixture()
+def enable_cors(app, monkeypatch):
+    monkeypatch.setitem(app.config, 'CORS_URL', 'https://bodhi.fedoraproject.org')
diff --git a/tests/test_api_v10.py b/tests/test_api_v10.py
index 8908db9..21dbdcf 100644
--- a/tests/test_api_v10.py
+++ b/tests/test_api_v10.py
@@ -1,10 +1,13 @@
 # SPDX-License-Identifier: GPL-2.0+
 
-import json
-from .utils import create_waiver
 import datetime
+import json
+
+import pytest
 from requests import ConnectionError, HTTPError
 from mock import patch, Mock
+
+from .utils import create_waiver
 from waiverdb import __version__
 
 
@@ -464,3 +467,67 @@ def test_about_endpoint(client):
     assert r.status_code == 200
     assert output['version'] == __version__
     assert output['auth_method'] == client.application.config['AUTH_METHOD']
+
+
+@pytest.mark.usefixtures('enable_cors')
+def test_cors_about(client, session):
+    r = client.get('/api/v1.0/about')
+
+    assert 'Access-Control-Allow-Origin' in list(r.headers.keys())
+    assert 'Access-Control-Allow-Headers' in list(r.headers.keys())
+    assert 'Access-Control-Allow-Method' in list(r.headers.keys())
+    assert r.headers['Access-Control-Allow-Origin'] == 'https://bodhi.fedoraproject.org'
+    assert r.headers['Access-Control-Allow-Headers'] == 'Content-Type'
+    assert r.headers['Access-Control-Allow-Method'] == 'POST, OPTIONS'
+
+    output = json.loads(r.get_data(as_text=True))
+    assert r.status_code == 200
+    assert output['version'] == __version__
+
+
+def test_no_cors_about(client, session):
+    r = client.get('/api/v1.0/about')
+
+    assert 'Access-Control-Allow-Origin' not in list(r.headers.keys())
+    assert 'Access-Control-Allow-Headers' not in list(r.headers.keys())
+    assert 'Access-Control-Allow-Method' not in list(r.headers.keys())
+
+    output = json.loads(r.get_data(as_text=True))
+    assert r.status_code == 200
+    assert output['version'] == __version__
+
+
+@pytest.mark.usefixtures('enable_cors')
+def test_cors_waivers(client, session):
+    for i in range(0, 3):
+        create_waiver(session, subject={"subject%d" % i: "%d" % i},
+                      testcase="case %d" % i, username='foo %d' % i,
+                      product_version='foo-%d' % i, comment='bla bla bla')
+    r = client.get('/api/v1.0/waivers/')
+
+    assert 'Access-Control-Allow-Origin' in list(r.headers.keys())
+    assert 'Access-Control-Allow-Headers' in list(r.headers.keys())
+    assert 'Access-Control-Allow-Method' in list(r.headers.keys())
+    assert r.headers['Access-Control-Allow-Origin'] == 'https://bodhi.fedoraproject.org'
+    assert r.headers['Access-Control-Allow-Headers'] == 'Content-Type'
+    assert r.headers['Access-Control-Allow-Method'] == 'POST, OPTIONS'
+
+    res_data = json.loads(r.get_data(as_text=True))
+    assert r.status_code == 200
+    assert len(res_data['data']) == 3
+
+
+def test_no_cors_waivers(client, session):
+    for i in range(0, 3):
+        create_waiver(session, subject={"subject%d" % i: "%d" % i},
+                      testcase="case %d" % i, username='foo %d' % i,
+                      product_version='foo-%d' % i, comment='bla bla bla')
+    r = client.get('/api/v1.0/waivers/')
+
+    assert 'Access-Control-Allow-Origin' not in list(r.headers.keys())
+    assert 'Access-Control-Allow-Headers' not in list(r.headers.keys())
+    assert 'Access-Control-Allow-Method' not in list(r.headers.keys())
+
+    res_data = json.loads(r.get_data(as_text=True))
+    assert r.status_code == 200
+    assert len(res_data['data']) == 3
diff --git a/waiverdb/api_v1.py b/waiverdb/api_v1.py
index ffe7a9b..10d6bd1 100644
--- a/waiverdb/api_v1.py
+++ b/waiverdb/api_v1.py
@@ -10,7 +10,7 @@ from sqlalchemy.sql.expression import func, cast
 
 from waiverdb import __version__
 from waiverdb.models import db, Waiver
-from waiverdb.utils import reqparse_since, json_collection, jsonp
+from waiverdb.utils import reqparse_since, json_collection, jsonp, insert_headers
 from waiverdb.fields import waiver_fields
 import waiverdb.auth
 
@@ -147,7 +147,8 @@ class WaiversResource(Resource):
                                                                       Waiver.testcase)
             query = query.filter(Waiver.id.in_(subquery))
         query = query.order_by(Waiver.timestamp.desc())
-        return json_collection(query, args['page'], args['limit'])
+        return insert_headers(
+            json_collection(query, args['page'], args['limit']))
 
     @jsonp
     @marshal_with(waiver_fields)
@@ -271,7 +272,7 @@ class WaiverResource(Resource):
         :statuscode 404: No waiver exists with that ID.
         """
         try:
-            return Waiver.query.get_or_404(waiver_id)
+            return insert_headers(Waiver.query.get_or_404(waiver_id))
         except Exception as NotFound:
             raise type(NotFound)('Waiver not found')
 
@@ -401,7 +402,7 @@ class GetWaiversBySubjectsAndTestcases(Resource):
             query = query.filter(Waiver.id.in_(subquery))
 
         query = query.order_by(Waiver.timestamp.desc())
-        return {'data': marshal(query.all(), waiver_fields)}
+        return insert_headers({'data': marshal(query.all(), waiver_fields)})
 
 
 class AboutResource(Resource):
@@ -428,7 +429,8 @@ class AboutResource(Resource):
         :statuscode 200: Currently running waiverdb software version and authentication
                          are returned.
         """
-        return {'version': __version__, 'auth_method': current_app.config['AUTH_METHOD']}
+        return insert_headers(
+            {'version': __version__, 'auth_method': current_app.config['AUTH_METHOD']})
 
 
 # set up the Api resource routing here
diff --git a/waiverdb/utils.py b/waiverdb/utils.py
index 30e0c02..fbd5e8c 100644
--- a/waiverdb/utils.py
+++ b/waiverdb/utils.py
@@ -123,6 +123,8 @@ def insert_headers(response):
     """ Insert the CORS headers for the give reponse if there are any
     configured for the application.
     """
+    if isinstance(response, dict):
+        response = jsonify(response)
     if current_app.config.get('CORS_URL'):
         response.headers['Access-Control-Allow-Origin'] = \
             current_app.config['CORS_URL']

