annotate roundup/cgi/TAL/TALDefs.py @ 8411:ef1ea918b07a reauth-confirm_id

feat(security): Add user confirmation/reauth for sensitive changes Auditors can raise Reauth(reason) exception to require the user to enter a token (e.g. account password) to verify the user is performing the change. Naming is subject to change. actions.py: New ReauthAction class handler and verifyPassword() method for overriding if needed. client.py: Handle Reauth exception by calling Client:reauth() method. Default client:reauth method. Add 'reauth' action declaration. exceptions.py: Define and document Reauth exception as a subclass of RoundupCGIException. templating.py: Define method utils.embed_form_fields(). The original form making a change to the database has a lot of form fields. These need to be resubmitted to Roundup as part of the form submission that verifies the user's password. This method turns all non file form fields into type=hidden inputs. It escapes the names and values to prevent XSS. For file form fields, it base64 encodes the contents and puts them in hidden pre blocks. The pre blocks have data attributes for the filename, filetype and the original field name. (Note the original field name is not used.) This stops the file content data (maybe binary e.g. jpegs) from breaking the html page. The reauth template runs JavaScript that turns the encoded data inside the pre tags back into a file. Then it adds a multiple file input control to the page and attaches all the files to it. This file input is submitted with the rest of the fields. _generic.reauth.html (multiple tracker templates): Generates a form with id=reauth_form to: display any message from the Reauth exception to the user (e.g. why user is asked to auth). get the user's password submit the form embed all the form data that triggered the reauth recreate any file data that was submitted as part of the form and generate a new file input to push the data to the back end It has the JavaScript routine (as an IIFE) that regenerates a file input without user intervention. All the TAL based tracker templates use the same form. There is also one for the jinja2 template. The JavaScript for both is the same. reference.txt: document embed_form_fields utility method. upgrading.txt: initial upgrading docs. TODO: Finalize naming. I am leaning toward ConfirmID rather than Reauth. Still looking for a standard name for this workflow. Externalize the javascript in _generic.reauth.html to a seperate file and use utils.readfile() to embed it or change the script to load it from a @@file url. Clean up upgrading.txt with just steps to implement and less feature detail/internals. Document internals/troubleshooting in reference.txt. Add tests using live server.
author John Rouillard <rouilj@ieee.org>
date Mon, 11 Aug 2025 14:01:12 -0400
parents 7172c201dec2
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
1 ##############################################################################
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
2 #
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
3 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
4 # All Rights Reserved.
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
5 #
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
6 # This software is subject to the provisions of the Zope Public License,
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
7 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
11 # FOR A PARTICULAR PURPOSE.
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
12 #
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
13 ##############################################################################
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
14 # Modifications for Roundup:
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
15 # 1. commented out ITALES references
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
16 """
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
17 Common definitions used by TAL and METAL compilation an transformation.
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
18 """
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
19
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
20 #from ITALES import ITALESErrorInfo
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
21
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
22 TAL_VERSION = "1.4"
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
23
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
24 XML_NS = "http://www.w3.org/XML/1998/namespace" # URI for XML namespace
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
25 XMLNS_NS = "http://www.w3.org/2000/xmlns/" # URI for XML NS declarations
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
26
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
27 ZOPE_TAL_NS = "http://xml.zope.org/namespaces/tal"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
28 ZOPE_METAL_NS = "http://xml.zope.org/namespaces/metal"
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
29 ZOPE_I18N_NS = "http://xml.zope.org/namespaces/i18n"
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
30
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
31 # This RE must exactly match the expression of the same name in the
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
32 # zope.i18n.simpletranslationservice module:
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
33 NAME_RE = "[a-zA-Z_][-a-zA-Z0-9_]*"
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
34
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
35 KNOWN_METAL_ATTRIBUTES = [
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
36 "define-macro",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
37 "use-macro",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
38 "define-slot",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
39 "fill-slot",
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
40 "slot",
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
41 ]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
42
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
43 KNOWN_TAL_ATTRIBUTES = [
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
44 "define",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
45 "condition",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
46 "content",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
47 "replace",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
48 "repeat",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
49 "attributes",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
50 "on-error",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
51 "omit-tag",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
52 "tal tag",
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
53 ]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
54
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
55 KNOWN_I18N_ATTRIBUTES = [
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
56 "translate",
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
57 "domain",
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
58 "target",
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
59 "source",
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
60 "attributes",
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
61 "data",
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
62 "name",
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
63 ]
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
64
5265
63868084b8bb Python 2 and 3 support. Convert Exception to BaseException. TAL and
John Rouillard <rouilj@ieee.org>
parents: 2348
diff changeset
65 class TALError(BaseException):
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
66
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
67 def __init__(self, msg, position=(None, None)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
68 assert msg != ""
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
69 self.msg = msg
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
70 self.lineno = position[0]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
71 self.offset = position[1]
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
72 self.filename = None
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
73
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
74 def setFile(self, filename):
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
75 self.filename = filename
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
76
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
77 def __str__(self):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
78 result = self.msg
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
79 if self.lineno is not None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
80 result = result + ", at line %d" % self.lineno
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
81 if self.offset is not None:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
82 result = result + ", column %d" % (self.offset + 1)
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
83 if self.filename is not None:
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
84 result = result + ', in file %s' % self.filename
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
85 return result
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
86
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
87 class METALError(TALError):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
88 pass
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
89
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
90 class TALESError(TALError):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
91 pass
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
92
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
93 class I18NError(TALError):
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
94 pass
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
95
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
96
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
97 class ErrorInfo:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
98
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
99 #__implements__ = ITALESErrorInfo
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
100
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
101 def __init__(self, err, position=(None, None)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
102 if isinstance(err, Exception):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
103 self.type = err.__class__
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
104 self.value = err
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
105 else:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
106 self.type = err
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
107 self.value = None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
108 self.lineno = position[0]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
109 self.offset = position[1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
110
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
111
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
112
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
113 import re
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
114 _attr_re = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
115 _subst_re = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
116 del re
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
117
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
118 def parseAttributeReplacements(arg, xml):
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
119 dict = {}
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
120 for part in splitParts(arg):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
121 m = _attr_re.match(part)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
122 if not m:
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
123 raise TALError("Bad syntax in attributes: " + repr(part))
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
124 name, expr = m.group(1, 2)
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
125 if not xml:
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
126 name = name.lower()
5381
0942fe89e82e Python 3 preparation: change "x.has_key(y)" to "y in x".
Joseph Myers <jsm@polyomino.org.uk>
parents: 5377
diff changeset
127 if name in dict:
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
128 raise TALError("Duplicate attribute name in attributes: " + repr(part))
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
129 dict[name] = expr
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
130 return dict
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
131
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
132 def parseSubstitution(arg, position=(None, None)):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
133 m = _subst_re.match(arg)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
134 if not m:
5377
12fe83f90f0d Python 3 preparation: use repr() instead of ``.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5265
diff changeset
135 raise TALError("Bad syntax in substitution text: " + repr(arg), position)
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
136 key, expr = m.group(1, 2)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
137 if not key:
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
138 key = "text"
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
139 return key, expr
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
140
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
141 def splitParts(arg):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
142 # Break in pieces at undoubled semicolons and
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
143 # change double semicolons to singles:
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
144 arg = arg.replace(";;", "\0")
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
145 parts = arg.split(';')
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
146 parts = [p.replace("\0", ";") for p in parts]
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
147 if len(parts) > 1 and not parts[-1].strip():
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
148 del parts[-1] # It ended in a semicolon
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
149 return parts
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
150
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
151 def isCurrentVersion(program):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
152 version = getProgramVersion(program)
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
153 return version == TAL_VERSION
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
154
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
155 def getProgramMode(program):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
156 version = getProgramVersion(program)
5420
7172c201dec2 Python 3 preparation: avoid obsolete types.*Type names.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5381
diff changeset
157 if (version == TAL_VERSION and isinstance(program[1], tuple) and
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
158 len(program[1]) == 2):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
159 opcode, mode = program[1]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
160 if opcode == "mode":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
161 return mode
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
162 return None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
163
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
164 def getProgramVersion(program):
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
165 if (len(program) >= 2 and
5420
7172c201dec2 Python 3 preparation: avoid obsolete types.*Type names.
Joseph Myers <jsm@polyomino.org.uk>
parents: 5381
diff changeset
166 isinstance(program[0], tuple) and len(program[0]) == 2):
1049
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
167 opcode, version = program[0]
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
168 if opcode == "version":
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
169 return version
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
170 return None
Richard Jones <richard@users.sourceforge.net>
parents:
diff changeset
171
2348
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
172 import re
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
173 _ent1_re = re.compile('&(?![A-Z#])', re.I)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
174 _entch_re = re.compile('&([A-Z][A-Z0-9]*)(?![A-Z0-9;])', re.I)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
175 _entn1_re = re.compile('&#(?![0-9X])', re.I)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
176 _entnx_re = re.compile('&(#X[A-F0-9]*)(?![A-F0-9;])', re.I)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
177 _entnd_re = re.compile('&(#[0-9][0-9]*)(?![0-9;])')
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
178 del re
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
179
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
180 def attrEscape(s):
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
181 """Replace special characters '&<>' by character entities,
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
182 except when '&' already begins a syntactically valid entity."""
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
183 s = _ent1_re.sub('&amp;', s)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
184 s = _entch_re.sub(r'&amp;\1', s)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
185 s = _entn1_re.sub('&amp;#', s)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
186 s = _entnx_re.sub(r'&amp;\1', s)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
187 s = _entnd_re.sub(r'&amp;\1', s)
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
188 s = s.replace('<', '&lt;')
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
189 s = s.replace('>', '&gt;')
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
190 s = s.replace('"', '&quot;')
8c2402a78bb0 beginning getting ZPT up to date: TAL first
Richard Jones <richard@users.sourceforge.net>
parents: 2005
diff changeset
191 return s

Roundup Issue Tracker: http://roundup-tracker.org/