plain 0.4.1__py3-none-any.whl → 0.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
plain/cli/cli.py CHANGED
@@ -5,6 +5,7 @@ import shutil
5
5
  import subprocess
6
6
  import sys
7
7
  import traceback
8
+ from importlib.metadata import entry_points
8
9
  from importlib.util import find_spec
9
10
  from pathlib import Path
10
11
 
@@ -14,7 +15,9 @@ from click.core import Command, Context
14
15
  import plain.runtime
15
16
  from plain import preflight
16
17
  from plain.assets.compile import compile_assets, get_compiled_path
18
+ from plain.exceptions import ImproperlyConfigured
17
19
  from plain.packages import packages
20
+ from plain.utils.crypto import get_random_string
18
21
 
19
22
  from .formatting import PlainContext
20
23
  from .packages import EntryPointGroup, InstalledPackagesGroup
@@ -248,7 +251,7 @@ def preflight_checks(package_label, deploy, fail_level, databases):
248
251
  msg = header + body + footer
249
252
  click.echo(msg, err=True)
250
253
  else:
251
- click.echo("Preflight check identified no issues.", err=True)
254
+ click.secho("Preflight check identified no issues.", err=True, fg="green")
252
255
 
253
256
 
254
257
  @plain_cli.command()
@@ -284,17 +287,10 @@ def compile(keep_original, fingerprint, compress):
284
287
  )
285
288
  sys.exit(1)
286
289
 
287
- # TODO make this an entrypoint instead
288
- # Compile our Tailwind CSS (including templates in plain itself)
289
- if find_spec("plain.tailwind") is not None:
290
- click.secho("Compiling Tailwind CSS", bold=True)
291
- result = subprocess.run(["plain", "tailwind", "compile", "--minify"])
290
+ for entry_point in entry_points(group="plain.assets.compile"):
291
+ click.secho(f"Running {entry_point.name}", bold=True)
292
+ result = entry_point.load()()
292
293
  print()
293
- if result.returncode:
294
- click.secho(
295
- f"Error compiling Tailwind CSS (exit {result.returncode})", fg="red"
296
- )
297
- sys.exit(result.returncode)
298
294
 
299
295
  # TODO also look in [tool.plain.compile.run]
300
296
 
@@ -406,6 +402,18 @@ def setting(setting_name):
406
402
  click.secho(f'Setting "{setting_name}" not found', fg="red")
407
403
 
408
404
 
405
+ @plain_cli.group()
406
+ def utils():
407
+ pass
408
+
409
+
410
+ @utils.command()
411
+ def generate_secret_key():
412
+ """Generate a new secret key"""
413
+ new_secret_key = get_random_string(50)
414
+ click.echo(new_secret_key)
415
+
416
+
409
417
  class AppCLIGroup(click.Group):
410
418
  """
411
419
  Loads app.cli if it exists as `plain app`
@@ -459,16 +467,31 @@ class PlainCommandCollection(click.CommandCollection):
459
467
  EntryPointGroup(),
460
468
  plain_cli,
461
469
  ]
462
- except Exception as e:
470
+ except ImproperlyConfigured as e:
463
471
  click.secho(
464
- f"Error setting up Plain CLI\n{e}",
472
+ str(e),
465
473
  fg="red",
466
474
  err=True,
467
475
  )
476
+
477
+ # None of these require the app to be setup
478
+ sources = [
479
+ EntryPointGroup(),
480
+ AppCLIGroup(),
481
+ plain_cli,
482
+ ]
483
+ except Exception as e:
468
484
  print("---")
469
485
  print(traceback.format_exc())
470
486
  print("---")
471
487
 
488
+ click.secho(
489
+ f"Error: {e}",
490
+ fg="red",
491
+ err=True,
492
+ )
493
+
494
+ # None of these require the app to be setup
472
495
  sources = [
473
496
  EntryPointGroup(),
474
497
  AppCLIGroup(),
plain/csrf/middleware.py CHANGED
@@ -9,7 +9,7 @@ import string
9
9
  from collections import defaultdict
10
10
  from urllib.parse import urlparse
11
11
 
12
- from plain.exceptions import DisallowedHost, ImproperlyConfigured
12
+ from plain.exceptions import DisallowedHost
13
13
  from plain.http import HttpHeaders, UnreadablePostError
14
14
  from plain.logs import log_response
15
15
  from plain.runtime import settings
@@ -242,44 +242,31 @@ class CsrfViewMiddleware:
242
242
  If the CSRF_USE_SESSIONS setting is false, raises InvalidTokenFormat if
243
243
  the request's secret has invalid characters or an invalid length.
244
244
  """
245
- if settings.CSRF_USE_SESSIONS:
246
- try:
247
- csrf_secret = request.session.get(CSRF_SESSION_KEY)
248
- except AttributeError:
249
- raise ImproperlyConfigured(
250
- "CSRF_USE_SESSIONS is enabled, but request.session is not "
251
- "set. SessionMiddleware must appear before CsrfViewMiddleware "
252
- "in MIDDLEWARE."
253
- )
245
+ try:
246
+ csrf_secret = request.COOKIES[settings.CSRF_COOKIE_NAME]
247
+ except KeyError:
248
+ csrf_secret = None
254
249
  else:
255
- try:
256
- csrf_secret = request.COOKIES[settings.CSRF_COOKIE_NAME]
257
- except KeyError:
258
- csrf_secret = None
259
- else:
260
- # This can raise InvalidTokenFormat.
261
- _check_token_format(csrf_secret)
250
+ # This can raise InvalidTokenFormat.
251
+ _check_token_format(csrf_secret)
252
+
262
253
  if csrf_secret is None:
263
254
  return None
264
255
  return csrf_secret
265
256
 
266
257
  def _set_csrf_cookie(self, request, response):
267
- if settings.CSRF_USE_SESSIONS:
268
- if request.session.get(CSRF_SESSION_KEY) != request.META["CSRF_COOKIE"]:
269
- request.session[CSRF_SESSION_KEY] = request.META["CSRF_COOKIE"]
270
- else:
271
- response.set_cookie(
272
- settings.CSRF_COOKIE_NAME,
273
- request.META["CSRF_COOKIE"],
274
- max_age=settings.CSRF_COOKIE_AGE,
275
- domain=settings.CSRF_COOKIE_DOMAIN,
276
- path=settings.CSRF_COOKIE_PATH,
277
- secure=settings.CSRF_COOKIE_SECURE,
278
- httponly=settings.CSRF_COOKIE_HTTPONLY,
279
- samesite=settings.CSRF_COOKIE_SAMESITE,
280
- )
281
- # Set the Vary header since content varies with the CSRF cookie.
282
- patch_vary_headers(response, ("Cookie",))
258
+ response.set_cookie(
259
+ settings.CSRF_COOKIE_NAME,
260
+ request.META["CSRF_COOKIE"],
261
+ max_age=settings.CSRF_COOKIE_AGE,
262
+ domain=settings.CSRF_COOKIE_DOMAIN,
263
+ path=settings.CSRF_COOKIE_PATH,
264
+ secure=settings.CSRF_COOKIE_SECURE,
265
+ httponly=settings.CSRF_COOKIE_HTTPONLY,
266
+ samesite=settings.CSRF_COOKIE_SAMESITE,
267
+ )
268
+ # Set the Vary header since content varies with the CSRF cookie.
269
+ patch_vary_headers(response, ("Cookie",))
283
270
 
284
271
  def _origin_verified(self, request):
285
272
  request_origin = request.META["HTTP_ORIGIN"]
@@ -289,7 +276,7 @@ class CsrfViewMiddleware:
289
276
  pass
290
277
  else:
291
278
  good_origin = "{}://{}".format(
292
- "https" if request.is_secure() else "http",
279
+ "https" if request.is_https() else "http",
293
280
  good_host,
294
281
  )
295
282
  if request_origin == good_origin:
@@ -331,11 +318,7 @@ class CsrfViewMiddleware:
331
318
  ):
332
319
  return
333
320
  # Allow matching the configured cookie domain.
334
- good_referer = (
335
- settings.SESSION_COOKIE_DOMAIN
336
- if settings.CSRF_USE_SESSIONS
337
- else settings.CSRF_COOKIE_DOMAIN
338
- )
321
+ good_referer = settings.CSRF_COOKIE_DOMAIN
339
322
  if good_referer is None:
340
323
  # If no cookie domain is configured, allow matching the current
341
324
  # host:port exactly if it's permitted by ALLOWED_HOSTS.
@@ -435,7 +418,7 @@ class CsrfViewMiddleware:
435
418
  return self._reject(
436
419
  request, REASON_BAD_ORIGIN % request.META["HTTP_ORIGIN"]
437
420
  )
438
- elif request.is_secure():
421
+ elif request.is_https():
439
422
  # If the Origin header wasn't provided, reject HTTPS requests if
440
423
  # the Referer header doesn't match an allowed value.
441
424
  #
plain/forms/fields.py CHANGED
@@ -14,7 +14,6 @@ from urllib.parse import urlsplit, urlunsplit
14
14
 
15
15
  from plain import validators
16
16
  from plain.exceptions import ValidationError
17
- from plain.runtime import settings
18
17
  from plain.utils import timezone
19
18
  from plain.utils.dateparse import parse_datetime, parse_duration
20
19
  from plain.utils.duration import duration_string
@@ -1001,7 +1000,7 @@ def from_current_timezone(value):
1001
1000
  When time zone support is enabled, convert naive datetimes
1002
1001
  entered in the current time zone to aware datetimes.
1003
1002
  """
1004
- if settings.USE_TZ and value is not None and timezone.is_naive(value):
1003
+ if value is not None and timezone.is_naive(value):
1005
1004
  current_timezone = timezone.get_current_timezone()
1006
1005
  try:
1007
1006
  if timezone._datetime_ambiguous_or_imaginary(value, current_timezone):
@@ -1025,6 +1024,6 @@ def to_current_timezone(value):
1025
1024
  When time zone support is enabled, convert aware datetimes
1026
1025
  to naive datetimes in the current time zone for display.
1027
1026
  """
1028
- if settings.USE_TZ and value is not None and timezone.is_aware(value):
1027
+ if value is not None and timezone.is_aware(value):
1029
1028
  return timezone.make_naive(value)
1030
1029
  return value
plain/forms/forms.py CHANGED
@@ -203,7 +203,8 @@ class BaseForm:
203
203
  self._errors[field].extend(error_list)
204
204
 
205
205
  # The field had an error, so removed it from the final data
206
- if field in self.cleaned_data:
206
+ # (we use getattr here so errors can be added to uncleaned forms)
207
+ if field in getattr(self, "cleaned_data", {}):
207
208
  del self.cleaned_data[field]
208
209
 
209
210
  def full_clean(self):
plain/http/request.py CHANGED
@@ -140,7 +140,7 @@ class HttpRequest:
140
140
  # Reconstruct the host using the algorithm from PEP 333.
141
141
  host = self.META["SERVER_NAME"]
142
142
  server_port = self.get_port()
143
- if server_port != ("443" if self.is_secure() else "80"):
143
+ if server_port != ("443" if self.is_https() else "80"):
144
144
  host = f"{host}:{server_port}"
145
145
  return host
146
146
 
@@ -267,12 +267,12 @@ class HttpRequest:
267
267
 
268
268
  @property
269
269
  def scheme(self):
270
- if settings.SECURE_PROXY_SSL_HEADER:
270
+ if settings.HTTPS_PROXY_HEADER:
271
271
  try:
272
- header, secure_value = settings.SECURE_PROXY_SSL_HEADER
272
+ header, secure_value = settings.HTTPS_PROXY_HEADER
273
273
  except ValueError:
274
274
  raise ImproperlyConfigured(
275
- "The SECURE_PROXY_SSL_HEADER setting must be a tuple containing "
275
+ "The HTTPS_PROXY_HEADER setting must be a tuple containing "
276
276
  "two values."
277
277
  )
278
278
  header_value = self.META.get(header)
@@ -281,7 +281,7 @@ class HttpRequest:
281
281
  return "https" if header_value.strip() == secure_value else "http"
282
282
  return self._get_scheme()
283
283
 
284
- def is_secure(self):
284
+ def is_https(self):
285
285
  return self.scheme == "https"
286
286
 
287
287
  @property
@@ -13,6 +13,15 @@ from .exception import convert_exception_to_response
13
13
  logger = logging.getLogger("plain.request")
14
14
 
15
15
 
16
+ # These middleware classes are always used by Plain.
17
+ BUILTIN_MIDDLEWARE = [
18
+ "plain.internal.middleware.headers.DefaultHeadersMiddleware",
19
+ "plain.internal.middleware.https.HttpsRedirectMiddleware",
20
+ "plain.internal.middleware.slash.RedirectSlashMiddleware",
21
+ "plain.csrf.middleware.CsrfViewMiddleware",
22
+ ]
23
+
24
+
16
25
  class BaseHandler:
17
26
  _view_middleware = None
18
27
  _middleware_chain = None
@@ -27,7 +36,10 @@ class BaseHandler:
27
36
 
28
37
  get_response = self._get_response
29
38
  handler = convert_exception_to_response(get_response)
30
- for middleware_path in reversed(settings.MIDDLEWARE):
39
+
40
+ middlewares = reversed(BUILTIN_MIDDLEWARE + settings.MIDDLEWARE)
41
+
42
+ for middleware_path in middlewares:
31
43
  middleware = import_string(middleware_path)
32
44
  mw_instance = middleware(handler)
33
45
 
@@ -0,0 +1,19 @@
1
+ from plain.runtime import settings
2
+
3
+
4
+ class DefaultHeadersMiddleware:
5
+ def __init__(self, get_response):
6
+ self.get_response = get_response
7
+
8
+ def __call__(self, request):
9
+ response = self.get_response(request)
10
+
11
+ for header, value in settings.DEFAULT_RESPONSE_HEADERS.items():
12
+ response.headers.setdefault(header, value)
13
+
14
+ # Add the Content-Length header to non-streaming responses if not
15
+ # already set.
16
+ if not response.streaming and not response.has_header("Content-Length"):
17
+ response.headers["Content-Length"] = str(len(response.content))
18
+
19
+ return response
@@ -0,0 +1,36 @@
1
+ import re
2
+
3
+ from plain.http import ResponsePermanentRedirect
4
+ from plain.runtime import settings
5
+
6
+
7
+ class HttpsRedirectMiddleware:
8
+ def __init__(self, get_response):
9
+ self.get_response = get_response
10
+
11
+ # Settings for https (compile regexes once)
12
+ self.https_redirect_enabled = settings.HTTPS_REDIRECT_ENABLED
13
+ self.https_redirect_host = settings.HTTPS_REDIRECT_HOST
14
+ self.https_redirect_exempt = [
15
+ re.compile(r) for r in settings.HTTPS_REDIRECT_EXEMPT
16
+ ]
17
+
18
+ def __call__(self, request):
19
+ """
20
+ Rewrite the URL based on settings.APPEND_SLASH
21
+ """
22
+
23
+ if redirect_response := self.maybe_https_redirect(request):
24
+ return redirect_response
25
+
26
+ return self.get_response(request)
27
+
28
+ def maybe_https_redirect(self, request):
29
+ path = request.path.lstrip("/")
30
+ if (
31
+ self.https_redirect_enabled
32
+ and not request.is_https()
33
+ and not any(pattern.search(path) for pattern in self.https_redirect_exempt)
34
+ ):
35
+ host = self.https_redirect_host or request.get_host()
36
+ return ResponsePermanentRedirect(f"https://{host}{request.get_full_path()}")
@@ -4,25 +4,7 @@ from plain.urls import is_valid_path
4
4
  from plain.utils.http import escape_leading_slashes
5
5
 
6
6
 
7
- class CommonMiddleware:
8
- """
9
- "Common" middleware for taking care of some basic operations:
10
-
11
- - URL rewriting: Based on the APPEND_SLASH setting,
12
- append missing slashes.
13
-
14
- - If APPEND_SLASH is set and the initial URL doesn't end with a
15
- slash, and it is not found in urlpatterns, form a new URL by
16
- appending a slash at the end. If this new URL is found in
17
- urlpatterns, return an HTTP redirect to this new URL; otherwise
18
- process the initial URL as usual.
19
-
20
- This behavior can be customized by subclassing CommonMiddleware and
21
- overriding the response_redirect_class attribute.
22
- """
23
-
24
- response_redirect_class = ResponsePermanentRedirect
25
-
7
+ class RedirectSlashMiddleware:
26
8
  def __init__(self, get_response):
27
9
  self.get_response = get_response
28
10
 
@@ -40,12 +22,7 @@ class CommonMiddleware:
40
22
  # If the given URL is "Not Found", then check if we should redirect to
41
23
  # a path with a slash appended.
42
24
  if response.status_code == 404 and self.should_redirect_with_slash(request):
43
- return self.response_redirect_class(self.get_full_path_with_slash(request))
44
-
45
- # Add the Content-Length header to non-streaming responses if not
46
- # already set.
47
- if not response.streaming and not response.has_header("Content-Length"):
48
- response.headers["Content-Length"] = str(len(response.content))
25
+ return ResponsePermanentRedirect(self.get_full_path_with_slash(request))
49
26
 
50
27
  return response
51
28
 
@@ -1,23 +1,7 @@
1
1
  from plain.exceptions import ImproperlyConfigured
2
2
  from plain.runtime import settings
3
3
 
4
- from .. import Error, Warning, register
5
-
6
- CROSS_ORIGIN_OPENER_POLICY_VALUES = {
7
- "same-origin",
8
- "same-origin-allow-popups",
9
- "unsafe-none",
10
- }
11
- REFERRER_POLICY_VALUES = {
12
- "no-referrer",
13
- "no-referrer-when-downgrade",
14
- "origin",
15
- "origin-when-cross-origin",
16
- "same-origin",
17
- "strict-origin",
18
- "strict-origin-when-cross-origin",
19
- "unsafe-url",
20
- }
4
+ from .. import Warning, register
21
5
 
22
6
  SECRET_KEY_INSECURE_PREFIX = "plain-insecure-"
23
7
  SECRET_KEY_MIN_LENGTH = 50
@@ -32,54 +16,18 @@ SECRET_KEY_WARNING_MSG = (
32
16
  f"vulnerable to attack."
33
17
  )
34
18
 
19
+ # TODO
35
20
  W001 = Warning(
36
- "You do not have 'plain.middleware.security.SecurityMiddleware' "
21
+ "You do not have 'plain.middleware.https.HttpsRedirectMiddleware' "
37
22
  "in your MIDDLEWARE so the SECURE_HSTS_SECONDS, "
38
23
  "SECURE_CONTENT_TYPE_NOSNIFF, SECURE_REFERRER_POLICY, "
39
- "SECURE_CROSS_ORIGIN_OPENER_POLICY, and SECURE_SSL_REDIRECT settings will "
24
+ "SECURE_CROSS_ORIGIN_OPENER_POLICY, and HTTPS_REDIRECT_ENABLED settings will "
40
25
  "have no effect.",
41
26
  id="security.W001",
42
27
  )
43
28
 
44
- W002 = Warning(
45
- "You do not have "
46
- "'plain.middleware.clickjacking.XFrameOptionsMiddleware' in your "
47
- "MIDDLEWARE, so your pages will not be served with an "
48
- "'x-frame-options' header. Unless there is a good reason for your "
49
- "site to be served in a frame, you should consider enabling this "
50
- "header to help prevent clickjacking attacks.",
51
- id="security.W002",
52
- )
53
-
54
- W004 = Warning(
55
- "You have not set a value for the SECURE_HSTS_SECONDS setting. "
56
- "If your entire site is served only over SSL, you may want to consider "
57
- "setting a value and enabling HTTP Strict Transport Security. "
58
- "Be sure to read the documentation first; enabling HSTS carelessly "
59
- "can cause serious, irreversible problems.",
60
- id="security.W004",
61
- )
62
-
63
- W005 = Warning(
64
- "You have not set the SECURE_HSTS_INCLUDE_SUBDOMAINS setting to True. "
65
- "Without this, your site is potentially vulnerable to attack "
66
- "via an insecure connection to a subdomain. Only set this to True if "
67
- "you are certain that all subdomains of your domain should be served "
68
- "exclusively via SSL.",
69
- id="security.W005",
70
- )
71
-
72
- W006 = Warning(
73
- "Your SECURE_CONTENT_TYPE_NOSNIFF setting is not set to True, "
74
- "so your pages will not be served with an "
75
- "'X-Content-Type-Options: nosniff' header. "
76
- "You should consider enabling this header to prevent the "
77
- "browser from identifying content types incorrectly.",
78
- id="security.W006",
79
- )
80
-
81
29
  W008 = Warning(
82
- "Your SECURE_SSL_REDIRECT setting is not set to True. "
30
+ "Your HTTPS_REDIRECT_ENABLED setting is not set to True. "
83
31
  "Unless your site should be available over both SSL and non-SSL "
84
32
  "connections, you may want to either set this setting True "
85
33
  "or configure a load balancer or reverse-proxy server "
@@ -102,99 +50,9 @@ W020 = Warning(
102
50
  id="security.W020",
103
51
  )
104
52
 
105
- W021 = Warning(
106
- "You have not set the SECURE_HSTS_PRELOAD setting to True. Without this, "
107
- "your site cannot be submitted to the browser preload list.",
108
- id="security.W021",
109
- )
110
-
111
- W022 = Warning(
112
- "You have not set the SECURE_REFERRER_POLICY setting. Without this, your "
113
- "site will not send a Referrer-Policy header. You should consider "
114
- "enabling this header to protect user privacy.",
115
- id="security.W022",
116
- )
117
-
118
- E023 = Error(
119
- "You have set the SECURE_REFERRER_POLICY setting to an invalid value.",
120
- hint="Valid values are: {}.".format(", ".join(sorted(REFERRER_POLICY_VALUES))),
121
- id="security.E023",
122
- )
123
-
124
- E024 = Error(
125
- "You have set the SECURE_CROSS_ORIGIN_OPENER_POLICY setting to an invalid "
126
- "value.",
127
- hint="Valid values are: {}.".format(
128
- ", ".join(sorted(CROSS_ORIGIN_OPENER_POLICY_VALUES)),
129
- ),
130
- id="security.E024",
131
- )
132
-
133
53
  W025 = Warning(SECRET_KEY_WARNING_MSG, id="security.W025")
134
54
 
135
55
 
136
- def _security_middleware():
137
- return "plain.middleware.security.SecurityMiddleware" in settings.MIDDLEWARE
138
-
139
-
140
- def _xframe_middleware():
141
- return (
142
- "plain.middleware.clickjacking.XFrameOptionsMiddleware" in settings.MIDDLEWARE
143
- )
144
-
145
-
146
- @register(deploy=True)
147
- def check_security_middleware(package_configs, **kwargs):
148
- passed_check = _security_middleware()
149
- return [] if passed_check else [W001]
150
-
151
-
152
- @register(deploy=True)
153
- def check_xframe_options_middleware(package_configs, **kwargs):
154
- passed_check = _xframe_middleware()
155
- return [] if passed_check else [W002]
156
-
157
-
158
- @register(deploy=True)
159
- def check_sts(package_configs, **kwargs):
160
- passed_check = not _security_middleware() or settings.SECURE_HSTS_SECONDS
161
- return [] if passed_check else [W004]
162
-
163
-
164
- @register(deploy=True)
165
- def check_sts_include_subdomains(package_configs, **kwargs):
166
- passed_check = (
167
- not _security_middleware()
168
- or not settings.SECURE_HSTS_SECONDS
169
- or settings.SECURE_HSTS_INCLUDE_SUBDOMAINS is True
170
- )
171
- return [] if passed_check else [W005]
172
-
173
-
174
- @register(deploy=True)
175
- def check_sts_preload(package_configs, **kwargs):
176
- passed_check = (
177
- not _security_middleware()
178
- or not settings.SECURE_HSTS_SECONDS
179
- or settings.SECURE_HSTS_PRELOAD is True
180
- )
181
- return [] if passed_check else [W021]
182
-
183
-
184
- @register(deploy=True)
185
- def check_content_type_nosniff(package_configs, **kwargs):
186
- passed_check = (
187
- not _security_middleware() or settings.SECURE_CONTENT_TYPE_NOSNIFF is True
188
- )
189
- return [] if passed_check else [W006]
190
-
191
-
192
- @register(deploy=True)
193
- def check_ssl_redirect(package_configs, **kwargs):
194
- passed_check = not _security_middleware() or settings.SECURE_SSL_REDIRECT is True
195
- return [] if passed_check else [W008]
196
-
197
-
198
56
  def _check_secret_key(secret_key):
199
57
  return (
200
58
  len(set(secret_key)) >= SECRET_KEY_MIN_UNIQUE_CHARACTERS
@@ -239,30 +97,3 @@ def check_debug(package_configs, **kwargs):
239
97
  @register(deploy=True)
240
98
  def check_allowed_hosts(package_configs, **kwargs):
241
99
  return [] if settings.ALLOWED_HOSTS else [W020]
242
-
243
-
244
- @register(deploy=True)
245
- def check_referrer_policy(package_configs, **kwargs):
246
- if _security_middleware():
247
- if settings.SECURE_REFERRER_POLICY is None:
248
- return [W022]
249
- # Support a comma-separated string or iterable of values to allow fallback.
250
- if isinstance(settings.SECURE_REFERRER_POLICY, str):
251
- values = {v.strip() for v in settings.SECURE_REFERRER_POLICY.split(",")}
252
- else:
253
- values = set(settings.SECURE_REFERRER_POLICY)
254
- if not values <= REFERRER_POLICY_VALUES:
255
- return [E023]
256
- return []
257
-
258
-
259
- @register(deploy=True)
260
- def check_cross_origin_opener_policy(package_configs, **kwargs):
261
- if (
262
- _security_middleware()
263
- and settings.SECURE_CROSS_ORIGIN_OPENER_POLICY is not None
264
- and settings.SECURE_CROSS_ORIGIN_OPENER_POLICY
265
- not in CROSS_ORIGIN_OPENER_POLICY_VALUES
266
- ):
267
- return [E024]
268
- return []
@@ -32,9 +32,5 @@ def check_csrf_middleware(package_configs, **kwargs):
32
32
 
33
33
  @register(deploy=True)
34
34
  def check_csrf_cookie_secure(package_configs, **kwargs):
35
- passed_check = (
36
- settings.CSRF_USE_SESSIONS
37
- or not _csrf_middleware()
38
- or settings.CSRF_COOKIE_SECURE is True
39
- )
35
+ passed_check = not _csrf_middleware() or settings.CSRF_COOKIE_SECURE is True
40
36
  return [] if passed_check else [W016]
plain/runtime/README.md CHANGED
@@ -54,12 +54,8 @@ SECRET_KEY = environ["SECRET_KEY"]
54
54
  DEBUG = environ.get("DEBUG", "false").lower() in ("true", "1", "yes")
55
55
 
56
56
  MIDDLEWARE = [
57
- "plain.middleware.security.SecurityMiddleware",
58
57
  "plain.sessions.middleware.SessionMiddleware",
59
- "plain.middleware.common.CommonMiddleware",
60
- "plain.csrf.middleware.CsrfViewMiddleware",
61
58
  "plain.auth.middleware.AuthenticationMiddleware",
62
- "plain.middleware.clickjacking.XFrameOptionsMiddleware",
63
59
  ]
64
60
 
65
61
  if DEBUG: