|
1 | 1 | """Mailcap file handling. See RFC 1524.""" |
2 | 2 |
|
3 | 3 | import os |
| 4 | +import warnings |
| 5 | +import re |
4 | 6 |
|
5 | 7 | __all__ = ["getcaps","findmatch"] |
6 | 8 |
|
| 9 | +# https://github.com/IronLanguages/ironpython3/issues/1274 |
| 10 | +# _find_unsafe = re.compile(r'[^\xa1-\U0010FFFF\w@+=:,./-]').search |
| 11 | +_find_unsafe = re.compile(r'[^\w@+=:,./-]').search |
| 12 | + |
| 13 | +class UnsafeMailcapInput(Warning): |
| 14 | + """Warning raised when refusing unsafe input""" |
| 15 | + |
7 | 16 | # Part 1: top-level interface. |
8 | 17 |
|
9 | 18 | def getcaps(): |
@@ -144,15 +153,22 @@ def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]): |
144 | 153 | entry to use. |
145 | 154 |
|
146 | 155 | """ |
| 156 | + if _find_unsafe(filename): |
| 157 | + msg = "Refusing to use mailcap with filename %r. Use a safe temporary filename." % (filename,) |
| 158 | + warnings.warn(msg, UnsafeMailcapInput) |
| 159 | + return None, None |
147 | 160 | entries = lookup(caps, MIMEtype, key) |
148 | 161 | # XXX This code should somehow check for the needsterminal flag. |
149 | 162 | for e in entries: |
150 | 163 | if 'test' in e: |
151 | 164 | test = subst(e['test'], filename, plist) |
| 165 | + if test is None: |
| 166 | + continue |
152 | 167 | if test and os.system(test) != 0: |
153 | 168 | continue |
154 | 169 | command = subst(e[key], MIMEtype, filename, plist) |
155 | | - return command, e |
| 170 | + if command is not None: |
| 171 | + return command, e |
156 | 172 | return None, None |
157 | 173 |
|
158 | 174 | def lookup(caps, MIMEtype, key=None): |
@@ -184,14 +200,23 @@ def subst(field, MIMEtype, filename, plist=[]): |
184 | 200 | elif c == 's': |
185 | 201 | res = res + filename |
186 | 202 | elif c == 't': |
| 203 | + if _find_unsafe(MIMEtype): |
| 204 | + msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype,) |
| 205 | + warnings.warn(msg, UnsafeMailcapInput) |
| 206 | + return None |
187 | 207 | res = res + MIMEtype |
188 | 208 | elif c == '{': |
189 | 209 | start = i |
190 | 210 | while i < n and field[i] != '}': |
191 | 211 | i = i+1 |
192 | 212 | name = field[start:i] |
193 | 213 | i = i+1 |
194 | | - res = res + findparam(name, plist) |
| 214 | + param = findparam(name, plist) |
| 215 | + if _find_unsafe(param): |
| 216 | + msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param, name) |
| 217 | + warnings.warn(msg, UnsafeMailcapInput) |
| 218 | + return None |
| 219 | + res = res + param |
195 | 220 | # XXX To do: |
196 | 221 | # %n == number of parts if type is multipart/* |
197 | 222 | # %F == list of alternating type and filename for parts |
|
0 commit comments