#Embedded file name: noradioactive.py import sys import os import getopt import BaseHTTPServer import urlparse import socket import cgi import logging import random import traceback import glob import urllib import urllib2 import hashlib import tempfile import pycassa import time import ConfigParser import SocketServer import threading import re HOME_STRING = ' Home' REGISTER_STRING = ' Register ' DOCUMENTATION_STRING = ' Nwongozo ' LOGOUT_STRING = ' Log out ' TITLE_STRING = ' radiation Monitoring System ' INTRO_STRING = ' This is a system to monitor your level of radiation ' LOGIN_STRING = ' Please log in using the form below ' LOGIN_FIELDSET_STRING = ' Enter' USERNAME_FIELD_STRING = 'user name ' PASSWORD_FIELD_STRING = ' secret word ' LOGIN_SUBMIT_STRING = ' Submit ' WELCOME_STRING = ' Welcome ' SERIAL_STRING = ' Number ' SUBMIT_READING_STRING = ' Please submit new radiation reading' FIELDSET_READING_STRING = ' Read ' RADIO_FIELD_STRING = ' Radioactive ' LOCATION_FIELD_STRING = ' Location' READING_SUBMIT_STRING = ' Record ' REGISTER_STRING = ' Register ' SERIAL_FIELD_STRING = ' serial number ' REGISTER_SUBMIT_STRING = ' Submit ' DATABASE_STRING = ' Primary data' DATA_STRING = ' Data ' SESSIONS_STRING = ' Sessions ' MANUAL_STRING = ' Documents ' MANUAL_DATA_STRING = ' This application is used to keep track of radiation levels in different areas . ' RECORD_READING_STRING = ' Record Read ' NOT_LOGGED_STRING = ' You are not inside. ' READING_RECORDED_STRING = ' Read success record. ' COLOCATED_WORKERS_STRING = ' same place workers ' REGISTRATION_STRING = ' No. ' USER_REGISTERED_STRING = ' User successfully added . ' USER_REGISTRATION_FAILED_STRING = ' user registeration failed' AUTHENTICATION_FAILED_STRING = ' Authentication failed. Please check that the provided username / secret word combination is correct . ' LOGIN_ERROR_STRING = ' Error occurred while processing your entry ' INVALID_LOGIN_STRING = ' Door invalid ' DATA_RECORDING_FAILED_STRING = ' Data recording failure ' LOGOUT_ERROR_STRING = ' an error occurred while logging out ' NOT_FOUND_STRING = ' Resource not found ' ERROR_STRING = ' an error occurred ' LOGGED_OUT_STRING = ' You have been logged out . ' class ThreadingHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): pass class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): home_path = '/' css_path = '/style.css' css_file = 'noradioactive.css' manual_path = '/manual' manual_file = 'noradioactive.doc' icon_path = '/favicon.ico' icon_file = 'noradioactive.ico' background_path = '/background.jpg' background_file = 'noradioactive.jpg' login_path = '/login' logout_path = '/logout' register_path = '/register' reading_path = '/reading' dump_path = '/dump' dump_allowed = False dump_auth_attr = 'auth' dump_auth_value = 'radioidar' secret = 'noradioactiveinjection' header = '\n\n\n\n \n %s\n \n \n\n \n
\n \n\n
\n' footer = '\n
\n \n
\n \n\n' def sanitize(self, string): allowed = ' ~{}[$%^&|<>]\'"+=*#@.,:;!?()-/_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' if string == None: return '' for c in string: if c not in allowed: return '' return string def background(self, params): self.send_response(200) self.send_header('Content-type', 'image/jpg') self.end_headers() try: data = open(self.background_file, 'r').read() self.wfile.write(data) except Exception as err: self.logger.error('Cannot access background image: %s' % str(err)) return 1 return 0 def style(self, params): self.send_response(200) self.send_header('Content-type', 'text/css') self.end_headers() try: data = open(self.css_file, 'r').read() self.wfile.write(data) except Exception as err: self.logger.error('Cannot access the CSS file: %s' % str(err)) return 1 return 0 def icon(self, params): self.send_response(200) self.send_header('Content-type', 'image/vnd.microsoft.icon') self.end_headers() try: f = open(self.icon_file, 'r') self.wfile.write(f.read()) f.close() except Exception as err: self.logger.debug('Cannot open icon: %s' % str(err)) def home(self, params): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (TITLE_STRING, TITLE_STRING)) session = self.auth() self.logger.debug('Session: %s' % session) if session == None: self.wfile.write('\n\n\n\n\n\n
\n

' + INTRO_STRING + '

\n


\n

' + LOGIN_STRING + '

\n\n
\n ' + LOGIN_FIELDSET_STRING + '\n
\n

' + USERNAME_FIELD_STRING + ':

\n

' + PASSWORD_FIELD_STRING + ':

\n

\n
\n
\n
\n
\n
\n') else: username = self.sessions.get(session).get('username') columns = self.data.get(username) self.wfile.write('\n

' + WELCOME_STRING + ' ' + username + ' [' + SERIAL_STRING + ': ' + columns.get('serial') + ']

\n
\n')
            for column in columns.keys():
                if column == 'serial':
                    continue
                if column == 'password':
                    continue
                self.wfile.write('\n%s: %s\n' % (column, columns.get(column)))

            self.wfile.write('\n
') self.wfile.write('\n

' + SUBMIT_READING_STRING + ':

\n
\n ' + FIELDSET_READING_STRING + '\n
\n

' + LOCATION_FIELD_STRING + ':

\n

' + RADIO_FIELD_STRING + ':

\n

\n
\n
\n") self.wfile.write(self.footer) def register(self, params): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (REGISTER_STRING, REGISTER_STRING)) self.wfile.write('\n
\n ' + REGISTER_STRING + '\n
\n

' + USERNAME_FIELD_STRING + ':

\n

' + PASSWORD_FIELD_STRING + ':

\n

' + SERIAL_FIELD_STRING + ':

\n

\n
\n
") self.wfile.write(self.footer) def manual(self, params): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (MANUAL_STRING, MANUAL_STRING)) self.wfile.write('

' + MANUAL_DATA_STRING + '

') self.wfile.write(self.footer) def dump(self, params): if not self.dump_allowed: return if not params.has_key(self.dump_auth_attr) or params[self.dump_auth_attr][0] != self.dump_auth_value: self.send_response(404) self.send_header('Content-type', 'text/html') self.end_headers() return self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (DATABASE_STRING, DATABASE_STRING)) result = self.data.get_range() self.wfile.write('

' + DATA_STRING + '

') self.wfile.write('\n
\n')
        for key, columns in result:
            self.wfile.write('\n%s:\n' % key)
            for column in columns:
                self.wfile.write('\n  %s: %s\n' % (str(column), columns[column]))

        self.wfile.write('\n
\n') self.wfile.write('

' + SESSIONS_STRING + '

') result = self.sessions.get_range() self.wfile.write('\n
\n')
        for key, columns in result:
            self.wfile.write('\n%s:\n' % key)
            for column in columns:
                self.wfile.write('\n  %s: %s\n' % (str(column), columns[column]))

        self.wfile.write('\n
\n') self.wfile.write(self.footer) def auth(self): cookies = self.headers.getheaders('Cookie') if cookies == None or len(cookies) == 0: return self.logger.debug('Received cookies: %s' % str(cookies)) session = None for cookie in cookies: try: attr_vals = cookie.split(';') for attr_val in attr_vals: attr_val = attr_val.strip() self.logger.debug('Considering attribute/value pair: %s' % str(attr_val)) attribute, value = attr_val.split('=') if attribute == 'session': session = value except Exception as err: self.logger.debug('Error in parsing cookie %s: %s' % (str(cookie), str(err))) return False if session == None: return try: columns = self.sessions.get(session) username = columns.get('username') except Exception as e: self.logger.error('Authentication failed for session: %s (%s)' % (session, str(e))) return return session def reading(self, form): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (RECORD_READING_STRING, RECORD_READING_STRING)) session = self.auth() if session == None: self.wfile.write('

' + NOT_LOGGED_STRING + '

') self.wfile.write(self.footer) return username = self.sessions.get(session).get('username') try: location = self.sanitize(form.getfirst('location')) radioactivity = self.sanitize(form.getfirst('radioactivity')) if location == '' or radioactivity == '': raise Exception('empty parameter(s)') self.logger.debug('Requested recording: location [%s] -> radioactivity [%s]' % (location, radioactivity)) if location != 'password' and location != 'serial': self.data.insert(username, {location: radioactivity}) self.wfile.write('\n

' + READING_RECORDED_STRING + '

\n') result = self.data.get_range() colos = list() for key, columns in result: if key == username: continue if columns.has_key(location): colos.append(key) if len(colos) > 0: self.wfile.write('\n

' + COLOCATED_WORKERS_STRING + ':

\n\n') self.wfile.write(self.footer) except Exception as err: self.logger.error('An error occurred when recording your reading: %s' % str(err)) self.wfile.write('\n

' + DATA_RECORDING_FAILED_STRING + ': %s.

\n' % self.sanitize(str(err))) self.wfile.write(self.footer) return def process_register(self, form): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (REGISTRATION_STRING, REGISTRATION_STRING)) try: username = form.getfirst('username') password = form.getfirst('password') serial = form.getfirst('serial') if username == '' or password == '' or serial == '' or username == None or password == None or serial == None: raise Exception('empty parameter(s)') username = self.sanitize(username.strip()) password = self.sanitize(password.strip()) serial = self.sanitize(serial.strip()) self.logger.debug('Requested registration with username [%s], password [%s], and serial [%s]' % (username, password, serial)) if password != '': md5 = hashlib.md5() md5.update(password) password = md5.hexdigest() self.data.insert(username, {'password': password}) if serial != '': self.data.insert(username, {'serial': serial}) self.wfile.write('\n

' + USER_REGISTERED_STRING + '

\n') self.wfile.write(self.footer) except Exception as err: self.logger.error('An error occurred when registering your account: %s' % str(err)) self.wfile.write('\n

' + USER_REGISTRATION_FAILED_STRING + ': %s.

\n' % self.sanitize(str(err))) self.wfile.write(self.footer) return def login(self, form): try: username = self.sanitize(form.getfirst('username')) password = self.sanitize(form.getfirst('password')) self.logger.debug('Requested login with username [%s] and password [%s]' % (username, password)) md5 = hashlib.md5() md5.update(password) password = md5.hexdigest() result = self.data.get(username) authenticated = True if not result.has_key('password'): authenticated = False if result['password'] != '' and result['password'] != password: authenticated = False if authenticated: md5 = hashlib.md5() md5.update(str(time.time()) + username + password + self.secret) session = md5.hexdigest() self.sessions.insert(session, {'username': username}) else: self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (INVALID_LOGIN_STRING, INVALID_LOGIN_STRING)) self.wfile.write('\n

' + AUTHENTICATION_FAILED_STRING + '

\n') self.wfile.write(self.footer) self.logger.error('Invalid login with username [%s] and password [%s]' % (username, password)) return except Exception as err: self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % (INVALID_LOGIN_STRING, INVALID_LOGIN_STRING)) self.wfile.write(LOGIN_ERROR_STRING + ': %s' % self.sanitize(str(err))) self.wfile.write(self.footer) self.logger.error('An error occurred in processing the login: %s' % str(err)) return self.send_response(303) self.send_header('Content-type', 'text/html') self.send_header('Location', '%s' % self.home_path) self.send_header('Set-Cookie', 'session=%s' % session) self.end_headers() def logout(self, params): try: self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(self.header % ('Logout', 'Logout')) session = self.auth() if session == None: self.wfile.write('

' + NOT_LOGGED_STRING + '

') self.wfile.write(self.footer) return self.sessions.remove(session) except Exception as err: self.wfile.write(LOGOUT_ERROR_STRING + ': %s' % self.sanitize(str(err))) self.wfile.write(self.footer) self.logger.error('An error occurred in processing the logout: %s' % str(err)) return self.wfile.write('\n

' + LOGGED_OUT_STRING + '

\n') self.wfile.write(self.footer) def do_GET(self): try: self.logger.debug('Received GET request with path: %s' % self.path) req = urlparse.urlparse(self.path) self.logger.debug('Received request resource: %s' % req.path) params = urlparse.parse_qs(req.query) self.logger.debug('Received parameters: %s' % str(params)) self.data = pycassa.columnfamily.ColumnFamily(RequestHandler.pool, RequestHandler.data_family) self.sessions = pycassa.columnfamily.ColumnFamily(RequestHandler.pool, RequestHandler.session_family) if req.path == self.home_path: self.home(params) return if req.path == self.register_path: self.register(params) return if req.path == self.css_path: self.style(params) return if req.path == self.background_path: self.background(params) return if req.path == self.icon_path: self.icon(params) return if req.path == self.dump_path: self.dump(params) return if req.path == self.manual_path: self.manual(params) return if req.path == self.logout_path: self.logout(params) return self.send_error(404, NOT_FOUND_STRING + ': %s' % self.sanitize(self.path)) return return except Exception as err: self.wfile.write(ERROR_STRING + ': ' + self.sanitize(str(err))) self.logger.error('An error occurred: ' + str(err)) et, ev, tb = sys.exc_info() traceback.print_tb(tb) return def do_POST(self): try: self.logger.debug('Received POST request with path: %s' % self.path) req = urlparse.urlparse(self.path) self.logger.debug('Received request resource: %s' % req.path) form = cgi.FieldStorage(fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers['Content-Type']}) self.logger.debug('Received parameters: %s' % str(form)) self.data = pycassa.columnfamily.ColumnFamily(RequestHandler.pool, RequestHandler.data_family) self.sessions = pycassa.columnfamily.ColumnFamily(RequestHandler.pool, RequestHandler.session_family) if req.path == self.login_path: self.login(form) return if req.path == self.register_path: self.process_register(form) return if req.path == self.reading_path: self.reading(form) return self.send_error(400, NOT_FOUND_STRING + ': %s' % self.sanitize(self.path)) return return except Exception as err: self.wfile.write(ERROR_STRING + ': ' + self.sanitize(str(err))) self.logger.error('An error occurred: ' + str(err)) return def usage(fname): print '%s [-d (debug)] [-p ] [-b ] [-k ] [-l ] [-i ]' % fname class Usage(Exception): def __init__(self, msg): self.msg = msg def main(argv = None): if argv is None: argv = sys.argv debug = False port = 9292 keyspace = 'myspace' data_family = 'data' session_family = 'sessions' log_level = logging.INFO log_file = None log_format = '%(asctime)s %(levelname)s: %(message)s' initialize = False init_file = None db_hostname = 'localhost' db_port = 9160 try: try: opts, args = getopt.getopt(argv[1:], 'dhp:k:l:i:') except getopt.error as msg: raise Usage(msg) for o, a in opts: if o == '-h': usage(os.path.basename(argv[0])) return 1 if o == '-d': debug = True if o == '-p': port = int(a) if o == '-b': db_hostname, db_port = split(a, ':') if o == '-k': keyspace = a if o == '-l': log_file = a if o == '-i': initialize = True init_file = a except Usage as err: logging.error('%s -- for help use -h' % err.msg) return 1 if debug: log_level = logging.DEBUG logging.basicConfig(level=log_level, filename=log_file, format=log_format) logger = logging.getLogger('noradioactive') RequestHandler.logger = logger logger.debug('Initialization...') try: logger.debug('Connecting to database %s:%s' % (str(db_hostname), str(db_port))) sysmgr = pycassa.system_manager.SystemManager('%s:%s' % (str(db_hostname), str(db_port))) logger.debug('Connection successful') keyspaces = sysmgr.list_keyspaces() logger.debug('Keyspaces: %s' % str(keyspaces)) if initialize and keyspace in keyspaces: logger.debug('Dropping keyspace: %s' % keyspace) sysmgr.drop_keyspace(keyspace) keyspaces = sysmgr.list_keyspaces() if keyspace not in keyspaces: logger.debug('Creating keyspace: %s' % keyspace) sysmgr.create_keyspace(keyspace, pycassa.system_manager.SIMPLE_STRATEGY, {'replication_factor': '1'}) families = sysmgr.get_keyspace_column_families(keyspace).keys() logger.debug('Families: %s' % str(families)) if data_family not in families: logger.debug('Creating column family: %s' % data_family) sysmgr.create_column_family(keyspace, data_family, column_validation_classes=None) if session_family not in families: logger.debug('Creating column family: %s' % session_family) sysmgr.create_column_family(keyspace, session_family, column_validation_classes=None) except Exception as err: logger.error('Failed to initialize the database: %s' % str(err)) et, ev, tb = sys.exc_info() traceback.print_tb(tb) return 1 try: RequestHandler.pool = pycassa.pool.ConnectionPool(keyspace, ['%s:%s' % (str(db_hostname), str(db_port))]) data = pycassa.columnfamily.ColumnFamily(RequestHandler.pool, data_family) session = pycassa.columnfamily.ColumnFamily(RequestHandler.pool, session_family) except Exception as e: logger.error('Missing or corrupted database %s: %s' % (keyspace, str(e))) return 1 if initialize: try: config = ConfigParser.ConfigParser() config.read(init_file) for username in config.sections(): password = config.get(username, 'password') serial = config.get(username, 'serial') md5 = hashlib.md5() md5.update(password) password = md5.hexdigest() data.insert(username, {'password': password, 'serial': serial}) except Exception as err: logger.error('Failed to initialize the database: %s' % str(err)) et, ev, tb = sys.exc_info() traceback.print_tb(tb) RequestHandler.data_family = data_family RequestHandler.session_family = session_family if debug: result = data.get_range() for key, columns in result: logger.debug('%s => %s' % (key, str(columns))) result = session.get_range() for key, columns in result: logger.debug('%s => %s' % (key, str(columns))) logger.debug('Listening on port %d' % port) try: logger.info('Starting noradioactive service...') httpd = ThreadingHTTPServer(('', port), RequestHandler) httpd.serve_forever() except KeyboardInterrupt: logger.info('Shutting down noradioactive...') httpd.socket.close() except Exception as e: logger.error('Error starting noradioactive: %s' % str(e)) return 1 if __name__ == '__main__': sys.exit(main())