Esempio n. 1
0
    def start(self):

        """
            most initialization operation of SecureDropbox UI is done here.
        """

        # get the local dropbox installation folder path
        dropbox_installation_folder = self.get_dropbox_installation_folder()

        # if there is no such a folder which indicate that dropbox client is not installed
        if not dropbox_installation_folder:

            # No local folder. Exit
            print "Dropbox client not installed. Please install the dropbox client before using Secure Dropbox"
            exit(0)
        else:

            # test the internet connection situation
            if not self.internet_on():

                # internet not accessible so switch to local mode
                print "Internet not accessible"

                # no ini file existed so no way to decrypt any existing file. Quit the programme
                if not self.local_ini_file_existed(dropbox_installation_folder):
                    print "No local configuration file existed. Quit Secure Dropbox"
                    exit(0)

                else:
                    # set to local mode. Read only
                    self.local_mode = True
                    print "Local configuration file existed. Secure Dropbox in Local Mode"

        # if programme in local mode, initialize in local way
        if self.local_mode:

            # call the same login UI
            username, password = self.login_UI()

            # but generate the SecureDropbox in local mode
            self.secure_dropbox = SecureDropboxLocal(username, password, dropbox_installation_folder)

        else:
            # internet accessible. Ask user if want to register a SecureDropbox accuont
            has_account = raw_input("Do you want to register a Secure Dropbox account?Y/N:").upper()

            if has_account.__eq__("Y"):

                # call the register UI and get username and password
                username, password = self.register_UI()

                if username and password:

                    # initialization in regular way. Registration procedure need cryptor to crypt the RSA private key
                    # SecureDropbox instance to generate RSA key pair and KMS handler to send the request to KMS server
                    self.secure_dropbox = SecureDropbox(username, password, dropbox_installation_folder)
                    self.secure_dropbox.cryptor = Cryptor()
                    self.secure_dropbox.KMS_handler = KMS_Handler(self.secure_dropbox.cryptor)

                    # process registration request
                    if self.secure_dropbox.register(username, password) == CONFIG.REGISTER_SUCCEED:
                        print "registration succeed"
                    else:
                        print "registration failed"
                else:
                    print "registration failed. Invalid input"

            # switch to login UI
            username, password = self.login_UI()

            # and regeneration a SecureDropbox instance again.
            # newly registered user and current user may not be the same one.
            self.secure_dropbox = SecureDropbox(username, password, dropbox_installation_folder)

        # initialize is the method that actually do most initialization work for SecureDropbox instance but not
        # the constructor
        if self.secure_dropbox.initialize():
            # get into a dead loop. It works as a command line interface
            while True:
                try:
                    command = raw_input("Secure Dropbox:").lower()
                    if command:
                        if self.local_mode:
                            self.local_commands[command]()
                        else:
                            self.commands[command]()
                    else:
                        continue
                except KeyError:
                    print "Invalid command. Input ? for help"
                except:
                    print traceback.format_exc()
        else:
            print "Initialization Failed"
Esempio n. 2
0
class SecureDropbox_UI(object):

    """
    Main user interface of SecureDropbox
    """

    def __init__(self):
        # secure dropbox instance to be generated in start method
        self.secure_dropbox = None

        # regular command set. Used when SecureDropbox in regular mode(Internet is accessible).
        self.commands = {
            "ls": self.file_list_processor,
            "load": self.file_load_processor,
            "share": self.file_sharing_processor,
            "delete": self.file_delete_processor,
            "read": self.file_read_processor,
            "shared": self.file_shared_processor,
            "read shared": self.file_read_shared_processor,
            "?": self.help,
        }

        # local command set. Used when SecureDropbox in local mode(Internet is not accessible)
        self.local_commands = {
            "ls": self.local_file_list_processor,
            # Methods for reading locally and remotely are the same
            "read": self.file_read_processor,
            "?": self.local_help,
        }

        # local mode is defautly set False but might be changed when detecting Internet connection situation.
        self.local_mode = False

    def local_file_list_processor(self):

        """
        print file list and return it to the invoker in local mode
        
        return:
            formated local file list information
        """

        # get generated file list
        file_list = self.secure_dropbox.show_file_list()

        width = 130
        sequence_width = 10
        filename_width = 80
        mod_time_width = 40
        header_format = "%-*s%-*s%-*s"
        data_format = "%-*s%-*s%-*s"

        print "=" * width
        print header_format % (sequence_width, "Seq", filename_width, "File", mod_time_width, "Last Modification")
        print "-" * width

        if file_list:
            for file_info in file_list:
                print data_format % (
                    sequence_width,
                    file_info[0],
                    filename_width,
                    file_info[1],
                    mod_time_width,
                    file_info[2],
                )
            return file_list
        else:
            print "No local file"
            return file_list

    def local_help(self):
        """
        print local mode help information
        """
        print """
            ls:           list the files in SecureDropbox
            read:         read loaded files in SecureDropbox
        """

    def file_list_processor(self):

        """
        print file list and return it to the invoker in regular mode
        
        return:
            formated local file list information
        """
        # get generated file list
        file_list = self.secure_dropbox.show_file_list()

        width = 150
        sequence_width = 10
        filename_width = 80
        mod_time_width = 40
        sync_flag_width = 20
        header_format = "%-*s%-*s%-*s%-*s"
        data_format = "%-*s%-*s%-*s%-*s"

        print "=" * width
        print header_format % (
            sequence_width,
            "Seq",
            filename_width,
            "File",
            mod_time_width,
            "Last Modification",
            sync_flag_width,
            "Sync Flag",
        )
        print "-" * width

        if file_list:
            for file_info in file_list:
                print data_format % (
                    sequence_width,
                    file_info[0],
                    filename_width,
                    file_info[1],
                    mod_time_width,
                    file_info[2],
                    sync_flag_width,
                    file_info[3],
                )
        return file_list

    def file_sharing_processor(self):
        """
        print sharable files information and get user input about who to share and which file to share
        """

        # get sharable files list
        file_list = self.file_list_processor()
        user_to_share_with = None
        file_to_share = None

        # get file sequence number to be shared
        file_sequence = raw_input("Please indicate the sequence number of file you want to share:")

        if not file_list:
            print "no local file to share"
            return

        if not file_sequence.isdigit():
            print "Invalid input"
            return

        file_sequence = int(file_sequence)

        # if file is out of synchronization(only existed locally but no corresponding record on KMS server), it cannot be shared
        # unsynchronized situation might owing to not proper file load operation like directly drag file into
        # Secure Dropbox Folder
        if file_list[file_sequence - 1][3] == "out-sync":
            print "out-sync file could not be shared with other users"
        elif file_sequence > 0 and file_sequence <= len(file_list):
            file_to_share = (
                self.secure_dropbox.secure_dropbox_folder_path + os.path.sep + file_list[file_sequence - 1][1]
            )
        else:
            print "file load failed"

        while True:
            # get sharing recipient's email address
            user_to_share_with = raw_input("User's email address to share with:")

            # must be a valid email address format
            if user_to_share_with and not re.match(r"[^@]+@[^@]+\.[^@]+", user_to_share_with):
                print "please input a valid email address"
            else:
                break

        if user_to_share_with and file_to_share:
            # share the file and print the result form KMS server
            a = self.secure_dropbox.share_file(user_to_share_with, file_to_share)
            if a:
                print "file sharing successfully!"
            else:
                print "file sharing failed"
        else:
            print "file load failed"

    def file_delete_processor(self):

        """
        get user's input about which file to be deleted
        """

        # generate and print local file list
        file_list = self.file_list_processor()
        if not file_list:
            print "No local file to delete"
            return

        # get file sequence number to be deleted
        file_sequence = raw_input("Please indicate the sequence number of file you want to delete:")
        if not file_sequence.isdigit():
            print "Invalid input"
            return

        file_sequence = int(file_sequence)
        if file_sequence > 0 and file_sequence <= len(file_list):
            path = self.secure_dropbox.secure_dropbox_folder_path + os.path.sep + file_list[file_sequence - 1][1]
        else:
            print "Invalid input"

        if path:
            # if a valid path, then delete the file and print result
            if self.secure_dropbox.delete_file(path):
                print "Selected file has been removed from Secure Dropbox"
            else:
                print "Selected file is not deleted successfully"
        else:
            print "file load failed"

    def file_load_processor(self):

        """
            load a file into SecureDropbox. Currently only .txt file is supported
        """

        # invoke a TKinter file loader. the path is returned as f.
        f = self.load_file_path()

        if f:
            # if f is a valid file path then load the corresponding file and print the result
            res = self.secure_dropbox.load_file_into_secure_dropbox(f)
            if res == CONFIG.UPLOAD_KEY_CHAIN_SUCCEED:
                print "upload doc keychain upload succeed"
            elif res == CONFIG.UPLOAD_KEY_CHAIN_EXISTED:
                print "upload doc keychain existed and replaced with new doc key."
            else:
                print "upload doc keychain failed"
        else:
            print "load file failed"

    def file_read_processor(self):

        """
        get user's input of which file to read and print the file content
        """

        # generate and print file list
        file_list = self.file_list_processor()

        # get user's input wrt sequence number of file to read
        file_sequence = raw_input("Please indicate the sequence number of file you want to read:")

        if not file_sequence.isdigit():
            print "Invalid input"
            return

        file_sequence = int(file_sequence)

        if not file_list:
            print "No file to read"
        elif file_list[file_sequence - 1][3] == "out-sync":
            print "Out sync file is not allow to read because it is not loaded via Secure Dropbox Client."
        elif file_sequence > 0 and file_sequence <= len(file_list):
            path = self.secure_dropbox.secure_dropbox_folder_path + os.path.sep + file_list[file_sequence - 1][1]

            # if a valid path, call the read_file function and print the decrypted content as result
            content = self.secure_dropbox.read_file(path)

            print content
        else:
            print "load file failed"

    def file_shared_processor(self):

        """
        print file shared by other with user himself.
        """

        # get shared file list
        shared_file_list = self.secure_dropbox.shared_file()

        width = 150
        sequence_width = 10
        doc_id_width = 80
        from_user_width = 60

        header_format = "%-*s%-*s%-*s"
        data_format = "%-*s%-*s%-*s"
        print "=" * width
        print header_format % (sequence_width, "Seq", doc_id_width, "Doc ID", from_user_width, "Shared By")
        print "-" * width

        if shared_file_list:
            for key in range(len(shared_file_list)):
                seq = key + 1
                print data_format % (
                    sequence_width,
                    str(seq),
                    doc_id_width,
                    shared_file_list[str(key)]["doc_id"],
                    from_user_width,
                    shared_file_list[str(key)]["from_user"],
                )

        return shared_file_list

    def file_read_shared_processor(self):

        """
        print file shared by other with user himself. 
        Then get user's input about sequence number of which shared file to read
        """

        flag = -1

        # get shared file list
        shared_file_list = self.file_shared_processor()

        # get user input of sn of shared file to read
        while shared_file_list and flag not in shared_file_list.keys():
            flag = raw_input("Please input the sequence number of shared file to read:")
            if flag.isdigit():
                flag = int(flag)
                flag -= 1
                flag = str(flag)
            else:
                print "invalid input"

        if flag != -1:
            # if valid input then print shared file content
            print self.secure_dropbox.read_shared_file(shared_file_list[flag]["doc_key"], shared_file_list[flag]["url"])
        else:
            print "Nothing to read"

    def login_UI(self):

        """
        get user's login information input and return the username and password to invoker.
        """
        # get the username
        username = None
        while not username:
            username = raw_input("Please input your account:")
            if username and not re.match(r"[^@]+@[^@]+\.[^@]+", username):
                print "username should be your email address same as you register on dropbox"
                username = None

        # get the password
        password = None
        while not password:
            password = getpass("Please input your password:"******"""
        get user's registration information input and return the username and password to invoker.
        """

        # get the username
        username = None
        while not username:
            username = raw_input("Please input your account to register:")
            if username and not re.match(r"[^@]+@[^@]+\.[^@]+", username):
                print "username should be your email address same as you register on dropbox"
                username = None

        # get the password
        password = None
        while not password:
            password = getpass("Please input your password to register:")

        # double check the password
        password_again = None
        while not password_again:
            password_again = getpass("Please confirm your password to register:")

        # if password are the same
        if username and password and password_again and password == password_again:
            return username, password
        else:
            print "invalid input. Different user password"
            return None, None

    def help(self):
        """
            print regular mode help information
        """

        print """
            ls:               list the files in SecureDropbox
            load:             load a plain text file to SecureDropbox
            share:            share the file in SecureDropbox with other SecureDropbox users
            delete:           delete files in SecureDropbox
            read:             read loaded files in SecureDropbox
            shared:           check files shared with me via SecureDropbox
            read shared:      read files shared with me via SecureDropbox
        """

    def start(self):

        """
            most initialization operation of SecureDropbox UI is done here.
        """

        # get the local dropbox installation folder path
        dropbox_installation_folder = self.get_dropbox_installation_folder()

        # if there is no such a folder which indicate that dropbox client is not installed
        if not dropbox_installation_folder:

            # No local folder. Exit
            print "Dropbox client not installed. Please install the dropbox client before using Secure Dropbox"
            exit(0)
        else:

            # test the internet connection situation
            if not self.internet_on():

                # internet not accessible so switch to local mode
                print "Internet not accessible"

                # no ini file existed so no way to decrypt any existing file. Quit the programme
                if not self.local_ini_file_existed(dropbox_installation_folder):
                    print "No local configuration file existed. Quit Secure Dropbox"
                    exit(0)

                else:
                    # set to local mode. Read only
                    self.local_mode = True
                    print "Local configuration file existed. Secure Dropbox in Local Mode"

        # if programme in local mode, initialize in local way
        if self.local_mode:

            # call the same login UI
            username, password = self.login_UI()

            # but generate the SecureDropbox in local mode
            self.secure_dropbox = SecureDropboxLocal(username, password, dropbox_installation_folder)

        else:
            # internet accessible. Ask user if want to register a SecureDropbox accuont
            has_account = raw_input("Do you want to register a Secure Dropbox account?Y/N:").upper()

            if has_account.__eq__("Y"):

                # call the register UI and get username and password
                username, password = self.register_UI()

                if username and password:

                    # initialization in regular way. Registration procedure need cryptor to crypt the RSA private key
                    # SecureDropbox instance to generate RSA key pair and KMS handler to send the request to KMS server
                    self.secure_dropbox = SecureDropbox(username, password, dropbox_installation_folder)
                    self.secure_dropbox.cryptor = Cryptor()
                    self.secure_dropbox.KMS_handler = KMS_Handler(self.secure_dropbox.cryptor)

                    # process registration request
                    if self.secure_dropbox.register(username, password) == CONFIG.REGISTER_SUCCEED:
                        print "registration succeed"
                    else:
                        print "registration failed"
                else:
                    print "registration failed. Invalid input"

            # switch to login UI
            username, password = self.login_UI()

            # and regeneration a SecureDropbox instance again.
            # newly registered user and current user may not be the same one.
            self.secure_dropbox = SecureDropbox(username, password, dropbox_installation_folder)

        # initialize is the method that actually do most initialization work for SecureDropbox instance but not
        # the constructor
        if self.secure_dropbox.initialize():
            # get into a dead loop. It works as a command line interface
            while True:
                try:
                    command = raw_input("Secure Dropbox:").lower()
                    if command:
                        if self.local_mode:
                            self.local_commands[command]()
                        else:
                            self.commands[command]()
                    else:
                        continue
                except KeyError:
                    print "Invalid command. Input ? for help"
                except:
                    print traceback.format_exc()
        else:
            print "Initialization Failed"

    def get_dropbox_installation_folder(self):

        """
            Search local folder by name and decide which on is the Dropbox client installation folder.
            Please make sure there is no same name folder as Dropbox client in your file system.
            It may cause every file is not load into the effective dropbox folder so that not synchronization
            of file sharing operation could be done
        """
        dropbox_folder = None

        # recursively search if there is a folder named Dropbox
        for dirname, dirnames, filenames in os.walk(os.path.expanduser("~")):
            for subdirname in dirnames:
                if subdirname == "Dropbox":
                    dropbox_folder = os.path.join(dirname, subdirname)
                    break
            if dropbox_folder:
                break

        # return the result
        return dropbox_folder

    def internet_on(self):
        """
            detect if Internet is accessible by visiting dropbox page.
        """
        try:
            # send http get request to dropbox homepage
            response = urllib2.urlopen("https://dropbox.com", timeout=20)
            return True
        # exception occurs if there is no response.
        except urllib2.URLError as err:
            pass
        return False

    def local_ini_file_existed(self, path):
        """
            detect if there is any ini_file existed in SecureDropbox Folder
        """
        temp_path = path + os.path.sep + "Secure Dropbox"
        if os.path.isdir(temp_path):
            filenames = os.listdir(temp_path)
            for element in filenames:
                if str(element).endswith(".ini"):
                    return True

        return False

    def load_file_path(self, enc_file=False):

        """
            call the TKinter file loader to get the selected file's path
        """
        Tk().withdraw()
        # show an "Open" dialog box and return the path to the selected file
        filename = askopenfilename(title="Select")
        try:
            # can only load file suffix is .txt
            if not enc_file:
                assert filename.endswith(".txt"), "currently only support txt files"
            else:
                assert filename.endswith(".enc"), "please select file ends up with .enc"
                assert filename.find(self.secure_dropbox.user.username), "please select your file only"
        except AssertionError, e:
            print e
            return None
        else: