As is, PyMailCGI avoids ever passing the POP account username
and password across the Net together in a single transaction, unless
the password is encrypted or obfuscated according to the modulesecret.py
on the server. This
module can be different everywhere PyMailCGI is installed, and it can
be uploaded anew in the future—encrypted passwords aren’t persistent
and live only for the duration of one mail-processing interaction
session. Provided you don’t publish your encryption code or its
private keys, your data will be as secure as the custom encryption
module you provide on your own server.
If you wish to use this system on the general Internet, you’ll
want to tailor this code. Ideally, you’ll install PyCrypto and change
the private key string. Barring that, replace
Example 16-13
with a custom
encryption coding scheme of your own or deploy one of the general
techniques mentioned earlier, such as an HTTPS-capable web server. In
any event, this software makes no guarantees; the security of your
password is ultimately up to you to ensure.
For additional information on security tools and techniques,
search the Web and consult books geared exclusively toward web
programming techniques. As this system is a prototype at large,
security is just one of a handful of limitations which would have to
be more fully addressed in a robust production-grade
version.
Because the encryption schemes used by PyMailCGI are
reversible, it is possible to reconstruct my email account’s
password if you happen to see its encrypted form in a screenshot,
unless the private key listed insecret.py
was different when the tests
shown were run. To sidestep this issue, the email account used in
all of this book’s examples is temporary and will be deleted by the
time you read these words. Please use an email account of your own
to test-drive the system.
Finally, the file
commonhtml.py
in
Example 16-14
is the Grand Central
Station of this application—its code is used and reused by just about
every other file in the system. Most of it is self-explanatory, and
we’ve already met most of its core idea earlier, in conjunction with the
CGI scripts that use it.
I haven’t talked about its
debugging
support,
though. Notice that this module assignssys.stderr
tosys.stdout
, in an attempt to force the text of
Python error messages to show up in the client’s browser (remember,
uncaught exceptions print details tosys.stderr
).
That works sometimes in PyMailCGI, but not always—the
error text shows up in a web page only if apage_header
call has already printed a
response preamble. If you want to see all error messages, make sure you
callpage_header
(or printContent-type:
lines manually) before any other
processing.
This module also defines functions that dump raw CGI environment
information to the browser (dumpstatepage
), and that wrap calls to
functions that print status messages so that their output isn’t added to
the HTML stream (runsilent
). A
version 3.0 addition also attempts to work around the fact that built-in
print calls can fail in Python 3.1 for some types of Unicode text (e.g.,
non-ASCII character sets in Internationalized headers), by forcing
binary mode and bytes for the output stream (print
).
I’ll leave the discovery of any remaining magic in the code in
Example 16-14
up to you, the
reader. You are hereby admonished to go forth and read, refer, and
reuse.
Example 16-14. PP4E\Internet\Web\PyMailCgi\cgi-bin\commonhtml.py
#!/usr/bin/python
"""
##################################################################################
generate standard page header, list, and footer HTML; isolates HTML generation
related details in this file; text printed here goes over a socket to the client,
to create parts of a new web page in the web browser; uses one print per line,
instead of string blocks; uses urllib to escape params in URL links auto from a
dict, but cgi.escape to put them in HTML hidden fields; some tools here may be
useful outside pymailcgi; could also return the HTML generated here instead of
printing it, so it could be included in other pages; could also structure as a
single CGI script that gets and tests a next action name as a hidden form field;
caveat: this system works, but was largely written during a two-hour layover at
the Chicago O'Hare airport: there is much room for improvement and optimization;
##################################################################################
"""
import cgi, urllib.parse, sys, os
# 3.0: Python 3.1 has issues printing some decoded str as text to stdout
import builtins
bstdout = open(sys.stdout.fileno(), 'wb')
def print(*args, end='\n'):
try:
builtins.print(*args, end=end)
sys.stdout.flush()
except:
for arg in args:
bstdout.write(str(arg).encode('utf-8'))
if end: bstdout.write(end.encode('utf-8'))
bstdout.flush()
sys.stderr = sys.stdout # show error messages in browser
from externs import mailconfig # from a package somewhere on server
from externs import mailtools # need parser for header decoding
parser = mailtools.MailParser() # one per process in this module
# my cgi address root
#urlroot = 'http://starship.python.net/~lutz/PyMailCgi/'
#urlroot = 'http://localhost:8000/cgi-bin/'
urlroot = '' # use minimal, relative paths
def pageheader(app='PyMailCGI', color='#FFFFFF', kind='main', info=''):
print('Content-type: text/html\n')
print('Read Programming Python (169 page) Page 169 Read Book Online,Top Vampire Books Read Online Free ' % (app, kind))
print('%s %s
' % (color, app, (info or kind)))
def pagefooter(root='pymailcgi.html'):
print('
')
print('print('align=left alt="[Python Logo]" border=0 hspace=15>')
print('Back to root page' % root)
print(' ')
def formatlink(cgiurl, parmdict):
"""
make "%url?key=val&key=val" query link from a dictionary;
escapes str() of all key and val with %xx, changes ' ' to +
note that URL escapes are different from HTML (cgi.escape)
"""
parmtext = urllib.parse.urlencode(parmdict) # calls parse.quote_plus
return '%s?%s' % (cgiurl, parmtext) # urllib does all the work
def pagelistsimple(linklist): # show simple ordered list
print('')
')
for (text, cgiurl, parmdict) in linklist:
link = formatlink(cgiurl, parmdict)
text = cgi.escape(text)
print('- \n %s' % (link, text))
print('
def pagelisttable(linklist): # show list in a table
print('
View | \n %s' % (link, text)) print(' |
---|
%s:' % hdr) print(' | print(' name=%s value="%s" %s size=60>' % (hdr, val, extra)) print(' |
---|---|
Text:') print(' |
Parts:') for filename in partnames: basename = os.path.basename(filename) filename = filename.replace('\\', '/') # Windows hack print(' | %s' % (filename, basename)) print(' |
---|
Attach:
')
for i in range(1, maxattach+1):
print('
' % i)
print('
', message)
print('Python Exception
', cgi.escape(str(exc_type)))
print('Exception details
', cgi.escape(str(exc_value)))
if stacktrace:
print('Exception traceback
')')
import traceback
traceback.print_tb(exc_tb, None, sys.stdout)
print('
Press the link below to return to the main page.
')