def process(req): """Process the welcome page. process(req) """ # We import functions "as needed" at this stage, making # sure they are private (underscore prefix). The exception # is "defs", which are just a bunch of defintions (although # any functions defined within it should be made private). from manage_kbasix import _is_session, _account_info from aux import _make_header, _fill_page from defs import kbasix, main # Here and in all other modules the module-specific definitions # take precedence over the 'kbasix' ones. info = {} info.update(kbasix) info.update(main) import logging logging.basicConfig(level=getattr(logging, \ info['log_level_'].upper()), \ filename=info['log_file_'], \ datefmt=info['log_dateformat_'], \ format=info['log_format_']) if repr(type(req)) != "<type 'mp_request'>": logging.critical('Invalid request for main.py') info['details'] = '[SYS] Invalid request [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) try: session = _is_session(req, required=False) info.update(session) if session['token']: profile = _account_info(info['login_name'], 'profile') info.update(profile) except Exception as reason: # We use 'warn' level because the '_is_session' redirect seems to # trigger this (if 'required=True') although it's not a critical # error. logging.warn(reason) info['details'] = '[SYS] Unable to verify session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) info['main_header'] = _make_header(info) try: return _initialize(info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to initialize the main \ page [%s].' % info['error_blurb_'] return _fill_page(info['error_page_'], info)
def process(req): """Process the logout page. process(req) """ from manage_kbasix import _is_session, _account_info from aux import _make_header, _fill_page from defs import kbasix, logout info = {} info.update(kbasix) info.update(logout) import logging logging.basicConfig(level = getattr(logging, \ info['log_level_'].upper()), \ filename = info['log_file_'], \ datefmt = info['log_dateformat_'], \ format = info['log_format_']) if repr(type(req)) != "<type 'mp_request'>": logging.critical('Invalid request for logout.py') info['details'] = '[SYS] Invalid request [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) try: session = _is_session(req, required=False) info.update(session) if session['token']: profile = _account_info(info['login_name'], 'profile') info.update(profile) except Exception as reason: logging.warn(reason) info['details'] = '[SYS] Unable to verify session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) info['main_header'] = _make_header(info) if not info['token']: info['title'] = 'Logout' info['class'] = 'information' info['details'] = 'You are not logged in.' info['status_button_1'] = '' info['status_button_2'] = '' return _fill_page(info['status_page_'], info) else: try: return _logout(info['token'], info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to terminate session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info)
def process(req): """Process the profile page. process(req) """ from manage_kbasix import _is_session, _account_info from aux import _make_header, _fill_page from defs import kbasix, profile info = {} info.update(kbasix) info.update(profile) import logging logging.basicConfig(level = getattr(logging, \ info['log_level_'].upper()), \ filename = info['log_file_'], \ datefmt = info['log_dateformat_'], \ format = info['log_format_']) if repr(type(req)) != "<type 'mp_request'>": logging.critical('Invalid request for profile.py') info['details'] = '[SYS] Invalid request [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) if not req.is_https(): info['details'] = 'You cannot edit your profile over an insecure \ connection.' return _fill_page(info['error_page_'], info) try: # We need to holdover (which only takes when "per_request_token" is # True) because we want to keep the restricted token generated when # a password is forgotten. Note that this check should be added to # any module which needs to be restricted. if 'token' in req.form and '-all-tk' not in req.form['token']: session = _is_session(req, required=True, holdover=True) else: session = _is_session(req, required=True) info.update(session) if session['token']: profile = _account_info(info['login_name'], 'profile') info.update(profile) except Exception as reason: logging.warn(reason) info['details'] = '[SYS] Unable to verify session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) info['main_header'] = _make_header(info) if 'start' in req.form: try: return _initialize(info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to initialize profile editor \ [%s].' % info['error_blurb_'] return _fill_page(info['error_page_'], info) elif 'action' not in req.form: info['details'] = 'No action specified trying to edit profile.' logging.warn(info['details']) return _fill_page(info['error_page_'], info) elif req.form['action'] == 'update': try: return _update(req, info) except UpdateError as reason: logging.critical(reason) info['details'] = '[SYS] Unable to update the profile \ [%s].' % info['error_blurb_'] return _fill_page(info['error_page_'], info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to update the profile [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) else: info['details'] = 'Unexpected action trying to update the profile.' logging.error(info['details']) return _fill_page(info['error_page_'], info)
def process(req): """Process the registration page. process(req) """ from manage_kbasix import _is_session, _account_info from aux import _make_header, _fill_page from defs import kbasix, register info = {} info.update(kbasix) info.update(register) import logging logging.basicConfig(level = getattr(logging, \ info['log_level_'].upper()), \ filename = info['log_file_'], \ datefmt = info['log_dateformat_'], \ format = info['log_format_']) if repr(type(req)) != "<type 'mp_request'>": logging.critical('Invalid request for register.py') info['details'] = '[SYS] Invalid request [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) if not req.is_https(): info['details'] = 'You cannot register over an insecure connection.' logging.info('Disallowed insecure access to register.py') return _fill_page(info['error_page_'], info) try: session = _is_session(req, required=False) info.update(session) if session['token']: profile = _account_info(info['login_name'], 'profile') info.update(profile) except Exception as reason: logging.warn(reason) info['details'] = '[SYS] Unable to verify session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) info['main_header'] = _make_header(info) if 'start' in req.form: try: return _initialize(info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to initialize registration \ [%s].' % info['error_blurb_'] return _fill_page(info['error_page_'], info) elif 'action' not in req.form: info['details'] = 'No action specified trying to register.' logging.warn(info['details']) return _fill_page(info['error_page_'], info) elif req.form['action'] == 'register': try: return _register(req, info) except RegisterError as reason: logging.critical(reason) info['details'] = '[SYS] Unable to register [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to register [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) else: info['details'] = 'Unexpected action trying to register.' logging.error(info['details']) return _fill_page(info['error_page_'], info)
def process(req): """Process the file manager page. process(req) """ from manage_kbasix import _is_session, _account_info from aux import _make_header, _fill_page from defs import kbasix, file_manager info = {} info.update(kbasix) info.update(file_manager) import logging logging.basicConfig(level = getattr(logging, \ info['log_level_'].upper()), \ filename = info['log_file_'], \ datefmt = info['log_dateformat_'], \ format = info['log_format_']) if repr(type(req)) != "<type 'mp_request'>": logging.critical('Invalid request for file_manager.py') info['details'] = '[SYS] Invalid request [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) if not req.is_https(): info['details'] = 'You cannot manage your file over an insecure \ connection.' logging.info('Disallowed insecure access to file_manager.py') return _fill_page(info['error_page_'], info) try: # The holdover is required if "per_request_token" is True, and # has no effect otherwise. This is needed due to the # client-generated download window (which has no concept of the # new request token). if 'action' in req.form and req.form['action'] == 'download': session = _is_session(req, required=True, holdover=True) else: session = _is_session(req, required=True) info.update(session) if session['token']: profile = _account_info(info['login_name'], 'profile') info.update(profile) except Exception as reason: logging.warn(reason) info['details'] = '[SYS] Unable to verify session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) info['main_header'] = _make_header(info) info['filter'] = False if 'start' in req.form: try: return _initialize(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to initialize the file manager \ [%s].' % info['error_blurb_'] return _fill_page(info['error_page_'], info) elif 'action' not in req.form: info['details'] = 'No action specified within the file manager.' logging.warn(info['details']) return _fill_page(info['error_page_'], info) elif req.form['action'] == 'filter': try: info['filter'] = True return _initialize(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] File manager error [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) elif req.form['action'] == 'copy_file': try: return _copy_file(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] File manager error [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) elif req.form['action'] == 'confirm_delete': try: return _confirm_delete(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] File manager error [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) elif req.form['action'] == 'delete': try: return _delete_file(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Error deleting file [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) elif req.form['action'] == 'confirm_bulk_delete': try: return _confirm_bulk_delete(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Error deleting files [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) elif req.form['action'] == 'download': try: return _download_file(req, info) except Exception as reason: # Not critical... user-end problem maybe? logging.error(reason) info['details'] = '[SYS] Unable to download file [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) else: info['details'] = 'Unexpected file manager action.' logging.error(info['details']) return _fill_page(info['error_page_'], info)
def process(req): """Process the upload page. process(req) """ # Note that upload sizes can be configured via "LimitRequestBody" # either in .htaccess or httpd.conf (the latter requires an httpd # restart). However, doing so results in mod_python spitting out a # nasty error message ("Request Entity Too Large") upon hitting said # limit. See: # # http://www.mail-archive.com/[email protected]/msg87503.html # # We can somewhat gracefully bypass this behaviour by adding the # following to .htaccess (using 10485760 as an example, and keeping in # mind that on a production server PythonDebug should be Off in # python.conf): # # PythonDebug Off # LimitRequestBody 10485760 # ErrorDocument 413 /path/upload.py/process?file_limit=10485760 # ErrorDocument 500 "An error was encountered" # # Note that the ErrorDocument message should be small (see below), and # that the paths are relative to DocumentRoot. # # Now, this approach has the following issue: the file is _not_ # uploaded to the server, but instead seems to be stored on the client # side and for some reason takes a long time to process there # (strangely so, as it's not being transferred). This method seems to # work well for medium-sized files above LimitRequestBody, but then for # huge files the client shows a connection reset error, explained here: # # http://stackoverflow.com/questions/4467443/limitrequestbody-doesnt-respond-with-413-for-large-file25mb # # In spite of the fact that the client feedback is slow (and that the # connection is reset on large files) it may be worthwhile to keep # since at least this does limit the resources used on the server, # including avoiding the "phantom file" space usage on /tmp (downloads # are stored in /tmp as a "phantom file", its usage can be obtained via # "df", freeing it requires an httpd restart if the upload happens to # die in one of the "file too large" manners [just closing the tab does # not cause this]). # # In short: # # 0 < size < LimitRequestBody: Upload success ful (OK) # LimitRequestBody < size < ~1GB : Upload limit message # (OK) # ~1GB < size < ~2GB : Connection reset (file # too large) # ~2GB < size : Browsers barf (file # too large) from manage_kbasix import _is_session, _account_info from aux import _make_header, _fill_page, _fill_str, _go_back_button from defs import kbasix, upload info = {} info.update(kbasix) info.update(upload) import logging logging.basicConfig(level = getattr(logging, \ info['log_level_'].upper()), \ filename = info['log_file_'], \ datefmt = info['log_dateformat_'], \ format = info['log_format_']) if repr(type(req)) != "<type 'mp_request'>": logging.critical('Invalid request for upload.py') info['details'] = '[SYS] Invalid request [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) # The following 'file_limit' comes from the 413 error redirect in # .htaccess. We disallow sneakiness by making sure the only argument # is an integer. Furthermore we note that no session handling is done # by this point (so, although the error page has no tokens, the browser # "Back" button will take us to our upload page, regardless of whether # the tokens are per-request). Since it's a dead-end error page with # no user-data it shouldn't affect the fact it lives outside a session's # scope. # Although the uploads page is session-protected the upload-limit error # message has to be public as we can't get the token from # .htaccess. Furthermore, it seems this message has to be pretty small # (returning "status_page_" gives "Request Entity Too Large"). Note # that the user temporarily loses their token, but has no other option # other than to browse "Back", recovering their token (also important # because HTTPS isn't required either). if 'file_limit' in req.form: file_limit = req.form['file_limit'].value try: max_size = int(file_limit) except: info['details'] = 'Non-numerical upload size' logging.error(info['details'] + ': %s' % file_limit) return _fill_page(info['error_page_'], info) info['details'] = 'The file you are trying to upload is too \ large (max size = %s bytes).' % max_size logging.warn(info['details']) return _fill_page(info['error_page_'], info) if not req.is_https(): info['details'] = 'You cannot upload over an insecure connection.' logging.info(info['details']) return _fill_page(info['error_page_'], info) try: session = _is_session(req, required=True) info.update(session) if session['token']: profile = _account_info(info['login_name'], 'profile') info.update(profile) except Exception as reason: logging.warn(reason) info['details'] = '[SYS] Unable to verify session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) info['main_header'] = _make_header(info) # User cannot upload if over-quota. try: (info['user_dir_size'], over_page) = \ _check_quota(req, 'upload', info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to determine quota [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) if info['user_dir_size'] < 0: return over_page if 'start' in req.form: try: return _initialize(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to initialize upload [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) elif 'action' not in req.form: info['details'] = 'No action specified trying to upload.' logging.warn(info['details']) return _fill_page(info['error_page_'], info) elif req.form['action'] == 'upload_file': try: return _get_file(req, info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Error uploading file [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) else: info['details'] = 'Unexpected action trying to upload.' logging.error(info['details']) return _fill_page(info['error_page_'], info)
def process(req): """Process the login page. process(req) """ from manage_kbasix import _is_session, _account_info from aux import _make_header, _fill_page from defs import kbasix, login info = {} info.update(kbasix) info.update(login) import logging logging.basicConfig(level = getattr(logging, \ info['log_level_'].upper()), \ filename = info['log_file_'], \ datefmt = info['log_dateformat_'], \ format = info['log_format_']) if repr(type(req)) != "<type 'mp_request'>": logging.critical('Invalid request for login.py') info['details'] = '[SYS] Invalid request [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) if not req.is_https(): info['details'] = 'You cannot login over an insecure connection.' logging.info('Disallowed insecure access to login.py') return _fill_page(info['error_page_'], info) try: session = _is_session(req, required=False) info.update(session) if session['token']: profile = _account_info(info['login_name'], 'profile') info.update(profile) except Exception as reason: logging.warn(reason) info['details'] = '[SYS] Unable to verify session [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) # This page should not appear to people who are already logged in. if info['token']: info['details'] = 'You are already logged in as "%s".' % \ info['user_name'] logging.debug(info['details']) return _fill_page(info['error_page_'], info) info['main_header'] = _make_header(info) # When a page requires a user to be logged-in it sends its name as # "referrer", which is obtained from "req.canonical_filename", and # spoofing it shouldn't gain anything other than attempting to access # a different URL (which can be done by editing the URL directly # anyways). if 'referrer' not in req.form: info['referrer'] = 'main.py' else: info['referrer'] = req.form['referrer'].value if 'start' in req.form: try: return _initialize(info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to open login page [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) elif 'action' not in req.form: info['details'] = 'No action specified trying to login.' logging.warn(info['details']) return _fill_page(info['error_page_'], info) elif req.form['action'] == 'login': try: if not req.form['user_name']: info['details'] = 'You must input your user name.' return _fill_page(info['error_page_'], info) else: info['user_name'] = req.form['user_name'].value info['login_name'] = info['user_name'].lower() return _login(req, info) except SendTokenError as reason: logging.critical(reason) info['details'] = '[SYS] Unable to email new token [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) except LoginError as reason: logging.critical(reason) info['details'] = '[SYS] Unable to login [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) except Exception as reason: logging.critical(reason) info['details'] = '[SYS] Unable to login [%s].' % \ info['error_blurb_'] return _fill_page(info['error_page_'], info) else: info['details'] = 'Unexpected action trying to login.' logging.error(info['details']) return _fill_page(info['error_page_'], info)