diff options
author | Nishanth Amuluru | 2011-01-11 22:41:51 +0530 |
---|---|---|
committer | Nishanth Amuluru | 2011-01-11 22:41:51 +0530 |
commit | b03203c8cb991c16ac8a3d74c8c4078182d0bb48 (patch) | |
tree | 7cf13b2deacbfaaec99edb431b83ddd5ea734a52 /parts/django/extras/csrf_migration_helper.py | |
parent | 0c50203cd9eb94b819883c3110922e873f003138 (diff) | |
download | pytask-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.py | 357 |
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) |