summaryrefslogtreecommitdiff
path: root/parts/django/extras/csrf_migration_helper.py
diff options
context:
space:
mode:
authorNishanth Amuluru2011-01-11 22:41:51 +0530
committerNishanth Amuluru2011-01-11 22:41:51 +0530
commitb03203c8cb991c16ac8a3d74c8c4078182d0bb48 (patch)
tree7cf13b2deacbfaaec99edb431b83ddd5ea734a52 /parts/django/extras/csrf_migration_helper.py
parent0c50203cd9eb94b819883c3110922e873f003138 (diff)
downloadpytask-b03203c8cb991c16ac8a3d74c8c4078182d0bb48.tar.gz
pytask-b03203c8cb991c16ac8a3d74c8c4078182d0bb48.tar.bz2
pytask-b03203c8cb991c16ac8a3d74c8c4078182d0bb48.zip
removed all the buildout files
Diffstat (limited to 'parts/django/extras/csrf_migration_helper.py')
-rw-r--r--parts/django/extras/csrf_migration_helper.py357
1 files changed, 0 insertions, 357 deletions
diff --git a/parts/django/extras/csrf_migration_helper.py b/parts/django/extras/csrf_migration_helper.py
deleted file mode 100644
index 6416193..0000000
--- a/parts/django/extras/csrf_migration_helper.py
+++ /dev/null
@@ -1,357 +0,0 @@
-#!/usr/bin/env python
-
-# This script aims to help developers locate forms and view code that needs to
-# use the new CSRF protection in Django 1.2. It tries to find all the code that
-# may need the steps described in the CSRF documentation. It does not modify
-# any code directly, it merely attempts to locate it. Developers should be
-# aware of its limitations, described below.
-#
-# For each template that contains at least one POST form, the following info is printed:
-#
-# <Absolute path to template>
-# AKA: <Aliases (relative to template directory/directories that contain it)>
-# POST forms: <Number of POST forms>
-# With token: <Number of POST forms with the CSRF token already added>
-# Without token:
-# <File name and line number of form without token>
-#
-# Searching for:
-# <Template names that need to be searched for in view code
-# (includes templates that 'include' current template)>
-#
-# Found:
-# <File name and line number of any view code found>
-#
-# The format used allows this script to be used in Emacs grep mode:
-# M-x grep
-# Run grep (like this): /path/to/my/virtualenv/python /path/to/django/src/extras/csrf_migration_helper.py --settings=mysettings /path/to/my/srcs
-
-
-# Limitations
-# ===========
-#
-# - All templates must be stored on disk in '.html' or '.htm' files.
-# (extensions configurable below)
-#
-# - All Python code must be stored on disk in '.py' files. (extensions
-# configurable below)
-#
-# - All templates must be accessible from TEMPLATE_DIRS or from the 'templates/'
-# directory in apps specified in INSTALLED_APPS. Non-file based template
-# loaders are out of the picture, because there is no way to ask them to
-# return all templates.
-#
-# - If you put the {% csrf_token %} tag on the same line as the <form> tag it
-# will be detected, otherwise it will be assumed that the form does not have
-# the token.
-#
-# - It's impossible to programmatically determine which forms should and should
-# not have the token added. The developer must decide when to do this,
-# ensuring that the token is only added to internally targetted forms.
-#
-# - It's impossible to programmatically work out when a template is used. The
-# attempts to trace back to view functions are guesses, and could easily fail
-# in the following ways:
-#
-# * If the 'include' template tag is used with a variable
-# i.e. {% include tname %} where tname is a variable containing the actual
-# template name, rather than {% include "my_template.html" %}.
-#
-# * If the template name has been built up by view code instead of as a simple
-# string. For example, generic views and the admin both do this. (These
-# apps are both contrib and both use RequestContext already, as it happens).
-#
-# * If the 'ssl' tag (or any template tag other than 'include') is used to
-# include the template in another template.
-#
-# - All templates belonging to apps referenced in INSTALLED_APPS will be
-# searched, which may include third party apps or Django contrib. In some
-# cases, this will be a good thing, because even if the templates of these
-# apps have been fixed by someone else, your own view code may reference the
-# same template and may need to be updated.
-#
-# You may, however, wish to comment out some entries in INSTALLED_APPS or
-# TEMPLATE_DIRS before running this script.
-
-# Improvements to this script are welcome!
-
-# Configuration
-# =============
-
-TEMPLATE_EXTENSIONS = [
- ".html",
- ".htm",
- ]
-
-PYTHON_SOURCE_EXTENSIONS = [
- ".py",
- ]
-
-TEMPLATE_ENCODING = "UTF-8"
-
-PYTHON_ENCODING = "UTF-8"
-
-# Method
-# ======
-
-# Find templates:
-# - template dirs
-# - installed apps
-#
-# Search for POST forms
-# - Work out what the name of the template is, as it would appear in an
-# 'include' or get_template() call. This can be done by comparing template
-# filename to all template dirs. Some templates can have more than one
-# 'name' e.g. if a directory and one of its child directories are both in
-# TEMPLATE_DIRS. This is actually a common hack used for
-# overriding-and-extending admin templates.
-#
-# For each POST form,
-# - see if it already contains '{% csrf_token %}' immediately after <form>
-# - work back to the view function(s):
-# - First, see if the form is included in any other templates, then
-# recursively compile a list of affected templates.
-# - Find any code function that references that template. This is just a
-# brute force text search that can easily return false positives
-# and fail to find real instances.
-
-
-import os
-import sys
-import re
-from optparse import OptionParser
-
-USAGE = """
-This tool helps to locate forms that need CSRF tokens added and the
-corresponding view code. This processing is NOT fool proof, and you should read
-the help contained in the script itself. Also, this script may need configuring
-(by editing the script) before use.
-
-Usage:
-
-python csrf_migration_helper.py [--settings=path.to.your.settings] /path/to/python/code [more paths...]
-
- Paths can be specified as relative paths.
-
- With no arguments, this help is printed.
-"""
-
-_POST_FORM_RE = \
- re.compile(r'(<form\W[^>]*\bmethod\s*=\s*(\'|"|)POST(\'|"|)\b[^>]*>)', re.IGNORECASE)
-_TOKEN_RE = re.compile('\{% csrf_token')
-
-def get_template_dirs():
- """
- Returns a set of all directories that contain project templates.
- """
- from django.conf import settings
- dirs = set()
- if ('django.template.loaders.filesystem.load_template_source' in settings.TEMPLATE_LOADERS
- or 'django.template.loaders.filesystem.Loader' in settings.TEMPLATE_LOADERS):
- dirs.update(map(unicode, settings.TEMPLATE_DIRS))
-
- if ('django.template.loaders.app_directories.load_template_source' in settings.TEMPLATE_LOADERS
- or 'django.template.loaders.app_directories.Loader' in settings.TEMPLATE_LOADERS):
- from django.template.loaders.app_directories import app_template_dirs
- dirs.update(app_template_dirs)
- return dirs
-
-def make_template_info(filename, root_dirs):
- """
- Creates a Template object for a filename, calculating the possible
- relative_filenames from the supplied filename and root template directories
- """
- return Template(filename,
- [filename[len(d)+1:] for d in root_dirs if filename.startswith(d)])
-
-
-class Template(object):
- def __init__(self, absolute_filename, relative_filenames):
- self.absolute_filename, self.relative_filenames = absolute_filename, relative_filenames
-
- def content(self):
- try:
- return self._content
- except AttributeError:
- fd = open(self.absolute_filename)
- try:
- content = fd.read().decode(TEMPLATE_ENCODING)
- except UnicodeDecodeError, e:
- message = '%s in %s' % (
- e[4], self.absolute_filename.encode('UTF-8', 'ignore'))
- raise UnicodeDecodeError(*(e.args[:4] + (message,)))
- fd.close()
- self._content = content
- return content
- content = property(content)
-
- def post_form_info(self):
- """
- Get information about any POST forms in the template.
- Returns [(linenumber, csrf_token added)]
- """
- matches = []
- for ln, line in enumerate(self.content.split("\n")):
- m = _POST_FORM_RE.search(line)
- if m is not None:
- matches.append((ln + 1, _TOKEN_RE.search(line) is not None))
- return matches
-
- def includes_template(self, t):
- """
- Returns true if this template includes template 't' (via {% include %})
- """
- for r in t.relative_filenames:
- if re.search(r'\{%\s*include\s+(\'|")' + re.escape(r) + r'(\1)\s*%\}', self.content):
- return True
- return False
-
- def related_templates(self):
- """
- Returns all templates that include this one, recursively. (starting
- with this one)
- """
- try:
- return self._related_templates
- except AttributeError:
- pass
-
- retval = set([self])
- for t in self.all_templates:
- if t.includes_template(self):
- # If two templates mutually include each other, directly or
- # indirectly, we have a problem here...
- retval = retval.union(t.related_templates())
-
- self._related_templates = retval
- return retval
-
- def __repr__(self):
- return repr(self.absolute_filename)
-
- def __eq__(self, other):
- return self.absolute_filename == other.absolute_filename
-
- def __hash__(self):
- return hash(self.absolute_filename)
-
-def get_templates(dirs):
- """
- Returns all files in dirs that have template extensions, as Template
- objects.
- """
- templates = set()
- for root in dirs:
- for (dirpath, dirnames, filenames) in os.walk(root):
- for f in filenames:
- if len([True for e in TEMPLATE_EXTENSIONS if f.endswith(e)]) > 0:
- t = make_template_info(os.path.join(dirpath, f), dirs)
- # templates need to be able to search others:
- t.all_templates = templates
- templates.add(t)
- return templates
-
-def get_python_code(paths):
- """
- Returns all Python code, as a list of tuples, each one being:
- (filename, list of lines)
- """
- retval = []
- for p in paths:
- if not os.path.isdir(p):
- raise Exception("'%s' is not a directory." % p)
- for (dirpath, dirnames, filenames) in os.walk(p):
- for f in filenames:
- if len([True for e in PYTHON_SOURCE_EXTENSIONS if f.endswith(e)]) > 0:
- fn = os.path.join(dirpath, f)
- fd = open(fn)
- content = [l.decode(PYTHON_ENCODING) for l in fd.readlines()]
- fd.close()
- retval.append((fn, content))
- return retval
-
-def search_python_list(python_code, template_names):
- """
- Searches python code for a list of template names.
- Returns a list of tuples, each one being:
- (filename, line number)
- """
- retval = []
- for tn in template_names:
- retval.extend(search_python(python_code, tn))
- retval = list(set(retval))
- retval.sort()
- return retval
-
-def search_python(python_code, template_name):
- """
- Searches Python code for a template name.
- Returns a list of tuples, each one being:
- (filename, line number)
- """
- retval = []
- for fn, content in python_code:
- for ln, line in enumerate(content):
- if ((u'"%s"' % template_name) in line) or \
- ((u"'%s'" % template_name) in line):
- retval.append((fn, ln + 1))
- return retval
-
-def main(pythonpaths):
- template_dirs = get_template_dirs()
- templates = get_templates(template_dirs)
- python_code = get_python_code(pythonpaths)
- for t in templates:
- # Logic
- form_matches = t.post_form_info()
- num_post_forms = len(form_matches)
- form_lines_without_token = [ln for (ln, has_token) in form_matches if not has_token]
- if num_post_forms == 0:
- continue
- to_search = [rf for rt in t.related_templates() for rf in rt.relative_filenames]
- found = search_python_list(python_code, to_search)
-
- # Display:
- print t.absolute_filename
- for r in t.relative_filenames:
- print u" AKA %s" % r
- print u" POST forms: %s" % num_post_forms
- print u" With token: %s" % (num_post_forms - len(form_lines_without_token))
- if form_lines_without_token:
- print u" Without token:"
- for ln in form_lines_without_token:
- print "%s:%d:" % (t.absolute_filename, ln)
- print
- print u" Searching for:"
- for r in to_search:
- print u" " + r
- print
- print u" Found:"
- if len(found) == 0:
- print " Nothing"
- else:
- for fn, ln in found:
- print "%s:%d:" % (fn, ln)
-
- print
- print "----"
-
-
-parser = OptionParser(usage=USAGE)
-parser.add_option("", "--settings", action="store", dest="settings", help="Dotted path to settings file")
-
-if __name__ == '__main__':
- options, args = parser.parse_args()
- if len(args) == 0:
- parser.print_help()
- sys.exit(1)
-
- settings = getattr(options, 'settings', None)
- if settings is None:
- if os.environ.get("DJANGO_SETTINGS_MODULE", None) is None:
- print "You need to set DJANGO_SETTINGS_MODULE or use the '--settings' parameter"
- sys.exit(1)
- else:
- os.environ["DJANGO_SETTINGS_MODULE"] = settings
-
- main(args)