1from django.http import HttpResponse, HttpResponseServerError 2from django.test import RequestFactory 3from django.test.utils import override_settings 4 5from csp.middleware import CSPMiddleware 6 7 8HEADER = 'Content-Security-Policy' 9mw = CSPMiddleware() 10rf = RequestFactory() 11 12 13def test_add_header(): 14 request = rf.get('/') 15 response = HttpResponse() 16 mw.process_response(request, response) 17 assert HEADER in response 18 19 20def test_exempt(): 21 request = rf.get('/') 22 response = HttpResponse() 23 response._csp_exempt = True 24 mw.process_response(request, response) 25 assert HEADER not in response 26 27 28@override_settings(CSP_EXCLUDE_URL_PREFIXES=('/inlines-r-us')) 29def text_exclude(): 30 request = rf.get('/inlines-r-us/foo') 31 response = HttpResponse() 32 mw.process_response(request, response) 33 assert HEADER not in response 34 35 36@override_settings(CSP_REPORT_ONLY=True) 37def test_report_only(): 38 request = rf.get('/') 39 response = HttpResponse() 40 mw.process_response(request, response) 41 assert HEADER not in response 42 assert HEADER + '-Report-Only' in response 43 44 45def test_dont_replace(): 46 request = rf.get('/') 47 response = HttpResponse() 48 response[HEADER] = 'default-src example.com' 49 mw.process_response(request, response) 50 assert response[HEADER] == 'default-src example.com' 51 52 53def test_use_config(): 54 request = rf.get('/') 55 response = HttpResponse() 56 response._csp_config = {'default-src': ['example.com']} 57 mw.process_response(request, response) 58 assert response[HEADER] == 'default-src example.com' 59 60 61def test_use_update(): 62 request = rf.get('/') 63 response = HttpResponse() 64 response._csp_update = {'default-src': ['example.com']} 65 mw.process_response(request, response) 66 assert response[HEADER] == "default-src 'self' example.com" 67 68 69@override_settings(CSP_IMG_SRC=['foo.com']) 70def test_use_replace(): 71 request = rf.get('/') 72 response = HttpResponse() 73 response._csp_replace = {'img-src': ['bar.com']} 74 mw.process_response(request, response) 75 policy_list = sorted(response[HEADER].split('; ')) 76 assert policy_list == ["default-src 'self'", "img-src bar.com"] 77 78 79@override_settings(DEBUG=True) 80def test_debug_exempt(): 81 request = rf.get('/') 82 response = HttpResponseServerError() 83 mw.process_response(request, response) 84 assert HEADER not in response 85 86 87def test_nonce_created_when_accessed(): 88 request = rf.get('/') 89 mw.process_request(request) 90 nonce = str(request.csp_nonce) 91 response = HttpResponse() 92 mw.process_response(request, response) 93 assert nonce in response[HEADER] 94 95 96def test_no_nonce_when_not_accessed(): 97 request = rf.get('/') 98 mw.process_request(request) 99 response = HttpResponse() 100 mw.process_response(request, response) 101 assert 'nonce-' not in response[HEADER] 102 103 104def test_nonce_regenerated_on_new_request(): 105 request1 = rf.get('/') 106 request2 = rf.get('/') 107 mw.process_request(request1) 108 mw.process_request(request2) 109 nonce1 = str(request1.csp_nonce) 110 nonce2 = str(request2.csp_nonce) 111 assert request1.csp_nonce != request2.csp_nonce 112 113 response1 = HttpResponse() 114 response2 = HttpResponse() 115 mw.process_response(request1, response1) 116 mw.process_response(request2, response2) 117 assert nonce1 not in response2[HEADER] 118 assert nonce2 not in response1[HEADER] 119 120 121@override_settings(CSP_INCLUDE_NONCE_IN=[]) 122def test_no_nonce_when_disabled_by_settings(): 123 request = rf.get('/') 124 mw.process_request(request) 125 nonce = str(request.csp_nonce) 126 response = HttpResponse() 127 mw.process_response(request, response) 128 assert nonce not in response[HEADER] 129