1 #!/usr/bin/env python 2 3 """ 4 Handle Confluence wiki requests employing special identifiers that should map to 5 wiki pages. This script also handles export actions because they also use page 6 identifiers. 7 """ 8 9 from urllib import quote 10 import cgi, os, sys 11 12 # Location of the mapping. 13 14 MAPPING_ID_TO_PAGE = "mapping-id-to-page.txt" 15 16 # An empty string means that the wiki is anchored at the site root. 17 18 URL_PREFIX = "" 19 DOWNLOAD_SCRIPT = "/download.py" 20 EXPORT_SCRIPT = "/export.py" 21 EXPORT_PDF_SCRIPT = "/exportpdf.py" 22 23 # Conversion of tiny identifiers to verbose identifiers. 24 25 from base64 import b64decode 26 from struct import unpack 27 28 def identifier(s): 29 30 "Extract an identifier from the given string 's'." 31 32 # Isolate numeric identifiers for things like downloads: 33 # /download/attachment/<pageid>/<filename>?<args> 34 35 if s.split("/")[0].isdigit(): 36 return s.split("/")[0] 37 38 # Reject strings that are too long for tiny identifiers. 39 40 if len(s) > 6: 41 return None 42 43 # Attempt to unpack tiny identifiers. 44 45 bytes = b64decode(s.replace("-", "/").replace("_", "+") + "=" * (6 - len(s))) 46 return str(unpack("<I", bytes + "\x00" * (4 - len(bytes)))[0]) 47 48 # Utility functions. 49 50 def fail(pageid): 51 print """\ 52 Status: 404 Page not found 53 Content-Type: text/html 54 55 <html> 56 <head><title>Bad Page Identifier</title></head> 57 <body> 58 <h1>Bad Page Identifier</h1> 59 <p>The identifier given in the URL%s does not seem to refer to a page in this wiki.</p> 60 </body> 61 </html> 62 """ % (pageid and " (%s)" % pageid or "") 63 sys.exit(0) 64 65 def redirect(pagename, download=None, export=False): 66 location = "%s/%s%s" % ( 67 URL_PREFIX, quote(pagename), 68 download and "?action=AttachFile&do=get&target=%s" % download 69 or export and "?action=ExportPDF" 70 or "" 71 ) 72 73 print """\ 74 Status: 302 Redirect to page 75 Location: %s 76 Content-Type: text/html 77 78 <html> 79 <head><title>Redirecting to Page</title></head> 80 <body> 81 <h1>Redirecting to Page</h1> 82 <p>If you see this message, try following <a href="%s">this link</a>.</p> 83 </body> 84 </html> 85 """ % (location, cgi.escape(location, True)) 86 sys.exit(0) 87 88 def find(f, pageid): 89 for line in f.xreadlines(): 90 columns = line.strip().split("\t") 91 if columns[0] == pageid: 92 return columns[1] 93 return None 94 95 def main(): 96 args = cgi.parse_qs(os.environ.get("QUERY_STRING", "")) 97 path = os.environ.get("PATH_INFO", "").strip("/") 98 script = os.environ.get("SCRIPT_NAME", "") 99 100 pageid = args.get("pageId", [None])[0] or identifier(path) 101 if pageid is None: 102 fail(pageid) 103 104 download = (script.endswith(DOWNLOAD_SCRIPT) or 105 script.endswith("/download/attachment") 106 ) and path.rsplit("/", 1)[1] or None 107 108 export = (script.endswith(EXPORT_SCRIPT) or 109 script.endswith("/pages/doexportpage.action") 110 ) and args.get("type", [""])[0] == "TYPE_PDF" or \ 111 (script.endswith(EXPORT_PDF_SCRIPT) or 112 script.endswith("/spaces/flyingpdf/pdfpageexport.action") 113 ) 114 115 f = open(MAPPING_ID_TO_PAGE) 116 try: 117 # With an identifier, find the corresponding page name. 118 119 pagename = find(f, pageid) 120 121 # Didn't find the page. 122 123 if not pagename: 124 fail(pageid) # exits 125 126 # Redirect to the page. 127 128 redirect(pagename, download, export) 129 130 finally: 131 f.close() 132 133 if __name__ == "__main__": 134 main() 135 136 # vim: tabstop=4 expandtab shiftwidth=4