Пример #1
0
    def _update_typo_cache_by_waitlist(self, typo_cache, freq_counts):
        """
        Updates the hash cache according to waitlist and clears the waitlist
        @typo_cache: a list of typos in the cache, and @freq_counts are the
        corresponding frequencies.

        returns: Updated typo_cache and their frequencies. Also applies the
        permutations.
        """
        logger.info("Updating TypoCache by Waitlist")
        good_typo_list = self._decrypt_n_filter_waitlist()
        mini, minf = min(enumerate(freq_counts), key=itemgetter(1))
        for typo, f in good_typo_list:
            if UserTypoDB.cache_insert_policy(minf, f):
                logger.debug("Inserting: {} @ {}".format(typo, mini))
                typo_cache[mini+1] = pwencrypt(typo, self._sk)
                freq_counts[mini] = max(minf + 1, f)  # TODO: Check
                mini, minf = min(enumerate(freq_counts), key=itemgetter(1))
            else:
                logger.debug("I miss you: {} ({} <-> {})".format(typo, minf, f))
                logger.debug("Freq counts: {}".format(freq_counts))

        # write the new typo_cache and freq_list
        # TODO: Apply permutation
        header_ctx = pkencrypt(self._pk, json.dumps({
            REAL_PW: self._pw,
            HMAC_SALT: urlsafe_b64encode(self._hmac_salt),
            FREQ_COUNTS: freq_counts
        }))
        logger.debug("Real pw={!r}".format(self._pw))

        self.set_in_auxtdb(HEADER_CTX, header_ctx)
        self.set_in_auxtdb(TYPO_CACHE, typo_cache)
        self.clear_waitlist()
Пример #2
0
def on_correct_password(typo_db, password):
    # log the entry of the original pwd
    logger.info("-^-")
    try:
        if not typo_db.is_typtop_init():
            logger.error("Typtop DB wasn't initiated yet!")
            typo_db.init_typtop(password)
            # the initialization is now part of the installation process
        check_system_status(typo_db)
        # correct password but db fails to see it
        is_match = typo_db.check(password)
        if not is_match:
            logger.debug("Changing system status to {}.".format(
                SYSTEM_STATUS_PW_CHANGED
            ))
            typo_db.set_status(SYSTEM_STATUS_PW_CHANGED)
            logger.info("Changing the system status because: match={}".format(is_match))
    except (ValueError, KeyError) as e:
        # most probably - an error of decryption as a result of pw change
        typo_db.set_status(SYSTEM_STATUS_PW_CHANGED)
        logger.exception("Key error raised. Probably a failure in decryption. Re-initializing...")
        typo_db.reinit_typtop(password)
    except Exception as e:
        logger.exception(
            "Unexpected error while on_correct_password:\n{}\n"
            .format(e)
        )
    # In order to avoid locking out - always return true for correct password
    return True
Пример #3
0
    def _decrypt_n_filter_waitlist(self):
        """Decrypts the waitlist and filters out the ones failed validity
        check. After that it combines the typos and returns a list of
        typos sorted by their frequency.

        return: [(typo_i, f_i)]
        """
        filtered_typos = defaultdict(int)
        sk = deserialize_sk(self._sk)
        assert self._pwent >= 0, \
            "pw={} is not initialized: {}".format(self._pw, self._pwent)
        ignore = set()
        install_id = self.get_installation_id()
        for typo_ctx in self.get_from_auxtdb(WAIT_LIST):  # , yaml.load):
            typo_txt = pkdecrypt(sk, typo_ctx)
            typo, ts = yaml.safe_load(typo_txt)
            # starts with installation id, then must be garbage
            if typo.startswith(install_id):
                continue
            self.insert_log(typo, in_cache=False, ts=ts)
            if typo in ignore: continue
            if self.validate(self._pw, typo):
                filtered_typos[typo] += 1
            else:
                logger.debug("Ignoring: {}".format(typo))
                ignore.add(typo)
        logger.info("Waitlist decrypted successfully")
        return sorted(filtered_typos.items(), key=lambda a: a[1], reverse=True)
Пример #4
0
 def get_last_unsent_logs_iter(self, force=False):
     """
     Check what was the last time the log has been sent,
     And returns whether the log should be sent
     """
     logger.debug("Getting last unsent logs")
     if not self.is_typtop_init():
         logger.debug("Could not send. Typtop not initiated")
         return False, iter([])
     if not self.is_allowed_upload():
         logger.info("Not sending logs because send status set to False")
         return False, iter([])
     last_sending = self.get_from_auxtdb(LOG_LAST_SENTTIME)  # , float)
     update_gap = self.get_from_auxtdb(LOG_SENT_PERIOD)  # , float)
     time_now = time.time()
     passed_enough_time = ((time_now - last_sending) >= update_gap)
     if not force and not passed_enough_time:
         logger.debug(
             "Not enough time has passed ({}) to send new logs.".format(
                 str(last_sending)))
         return False, iter([])
     log_t = self._db[logT]
     try:
         new_logs = iter(
             log_t)  # .find(log_t.table.columns.ts >= last_sending)
         logger.info("Prepared new logs to be sent, from {} to {}".format(
             str(last_sending), str(time_now)))
         return True, new_logs
     except AttributeError:
         return False, iter([])
Пример #5
0
    def _decrypt_n_filter_waitlist(self):
        """Decrypts the waitlist and filters out the ones failed validity
        check. After that it combines the typos and returns a list of
        typos sorted by their frequency.

        return: [(typo_i, f_i)]
        """
        filtered_typos = defaultdict(int)
        sk = deserialize_sk(self._sk)
        assert self._pwent >= 0, \
            "pw={} is not initialized: {}".format(self._pw, self._pwent)
        ignore = set()
        install_id = self.get_installation_id()
        for typo_ctx in self.get_from_auxtdb(WAIT_LIST): # , yaml.load):
            typo_txt = pkdecrypt(sk, typo_ctx)
            typo, ts = yaml.safe_load(typo_txt)
            # starts with installation id, then must be garbage
            if typo.startswith(install_id):
                continue
            self.insert_log(typo, in_cache=False, ts=ts)
            if typo in ignore: continue
            if self.validate(self._pw, typo):
                filtered_typos[typo] += 1
            else:
                logger.debug("Ignoring: {}".format(typo))
                ignore.add(typo)
        logger.info("Waitlist decrypted successfully")
        return sorted(
            filtered_typos.items(), key=lambda a: a[1], reverse=True
        )
Пример #6
0
def on_correct_password(typo_db, password):
    # log the entry of the original pwd
    logger.info("-^-")
    try:
        if not typo_db.is_typtop_init():
            logger.error("Typtop DB wasn't initiated yet!")
            typo_db.init_typtop(password)
            # the initialization is now part of the installation process
        check_system_status(typo_db)
        # correct password but db fails to see it
        is_match = typo_db.check(password)
        if not is_match:
            logger.debug("Changing system status to {}.".format(
                SYSTEM_STATUS_PW_CHANGED))
            typo_db.set_status(SYSTEM_STATUS_PW_CHANGED)
            logger.info("Changing the system status because: match={}".format(
                is_match))
    except (ValueError, KeyError) as e:
        # most probably - an error of decryption as a result of pw change
        typo_db.set_status(SYSTEM_STATUS_PW_CHANGED)
        logger.exception(
            "Key error raised. Probably a failure in decryption. Re-initializing..."
        )
        typo_db.reinit_typtop(password)
    except Exception as e:
        logger.exception(
            "Unexpected error while on_correct_password:\n{}\n".format(e))
    # In order to avoid locking out - always return true for correct password
    return True
Пример #7
0
 def get_last_unsent_logs_iter(self, force=False):
     """
     Check what was the last time the log has been sent,
     And returns whether the log should be sent
     """
     logger.debug("Getting last unsent logs")
     if not self.is_typtop_init():
         logger.debug("Could not send. Typtop not initiated")
         return False, iter([])
     if not self.is_allowed_upload():
         logger.info("Not sending logs because send status set to False")
         return False, iter([])
     last_sending = self.get_from_auxtdb(LOG_LAST_SENTTIME)  # , float)
     update_gap = self.get_from_auxtdb(LOG_SENT_PERIOD)  # , float)
     time_now = time.time()
     passed_enough_time = ((time_now - last_sending) >= update_gap)
     if not force and not passed_enough_time:
         logger.debug("Not enough time has passed ({}) to send new logs."
                      .format(str(last_sending)))
         return False, iter([])
     log_t = self._db[logT]
     try:
         new_logs = iter(log_t)  # .find(log_t.table.columns.ts >= last_sending)
         logger.info("Prepared new logs to be sent, from {} to {}".format(
             str(last_sending), str(time_now))
         )
         return True, new_logs
     except AttributeError:
         return False, iter([])
Пример #8
0
 def allow(self, what, how):
     self.assert_initialized()
     assert how in (True, False, 0, 1), "Expects a boolean"
     how = True if how else False
     self.set_in_auxtdb(what, how)
     state = "ON" if how else "OFF"
     logger.info("typtop::{} set to {}".format(what, state))
Пример #9
0
def on_wrong_password(typo_db, password):
    logger.info("-\/-")
    is_match = False
    try:
        if not typo_db.is_typtop_init():
            logger.error("Typtop DB wasn't initiated yet!")
            # typo_db.init_typtop(password)
            return False
        check_system_status(typo_db)
        is_match = typo_db.check(password)
        # password has changed and this is an old password
        if is_match and typo_db.is_real_pw(password):
            logger.info(
                "Password changed, old password entered. Re-initializing..")
            typo_db.reinit_typtop(urlsafe_b64encode(os.urandom(16)))
            return False
    except (ValueError, KeyError) as e:
        # probably  failure in decryption
        logger.exception(
            "Error!! Probably failure in decryption. Re-initializing...")
        typo_db.reinit_typtop(password)
    except Exception as e:
        logger.exception("Unexpected error while on_wrong_password:\n{}\n"\
                         .format(e))
        print("TypToP is not initialized.\n $ sudo typtop --init")
    return is_match
Пример #10
0
 def allow(self, what, how):
     self.assert_initialized()
     assert how in (True, False, 0, 1), "Expects a boolean"
     how = True if how else False
     self.set_in_auxtdb(what, how)
     state = "ON" if how else "OFF"
     logger.info("typtop::{} set to {}".format(what, state))
Пример #11
0
 def __del__(self):
     tmp_f = self._db_path + '.tmp'
     with open(tmp_f, 'wb') as f:
         json.dump(self._db, f, indent=2)
         f.flush(); os.fsync(f.fileno())
     os.rename(tmp_f, self._db_path)
     change_db_ownership(self._db_path)
     logger.info("---UserTypoDB deleted---")
Пример #12
0
 def __del__(self):
     tmp_f = self._db_path + '.tmp'
     with open(tmp_f, 'wb') as f:
         json.dump(self._db, f, indent=2)
         f.flush()
         os.fsync(f.fileno())
     os.rename(tmp_f, self._db_path)
     change_db_ownership(self._db_path)
     logger.info("---UserTypoDB deleted---")
Пример #13
0
 def check_login_count(self, update=False):
     # type: (boolean) -> boolean
     """Keeps track of how many times the user has successfully logged in."""
     count_entry = self.get_from_auxtdb(LOGIN_COUNT) + 1
     if update:
         self.set_in_auxtdb(LOGIN_COUNT, count_entry)
     allowed = count_entry > NUMBER_OF_ENTRIES_TO_ALLOW_TYPO_LOGIN
     if not allowed:
         logger.info("Checking login count. Allowed = {}".format(allowed))
     return allowed
Пример #14
0
 def check_login_count(self, update=False):
     # type: (boolean) -> boolean
     """Keeps track of how many times the user has successfully logged in."""
     count_entry = self.get_from_auxtdb(LOGIN_COUNT) + 1
     if update:
         self.set_in_auxtdb(LOGIN_COUNT, count_entry)
     allowed = count_entry > NUMBER_OF_ENTRIES_TO_ALLOW_TYPO_LOGIN
     if not allowed:
         logger.info("Checking login count. Allowed = {}".format(allowed))
     return allowed
Пример #15
0
    def __init__(self, user, debug_mode=False):
        # type: (str, bool) -> None
        assert is_user(user), "User {!r} does not exists".format(user)

        # Disable Typtop for root
        # assert pwd.getpwnam(user).pw_uid != 0,\
        #     "Currently Typtop is disabled for {} user.".format(user)

        self._user = user  # this is a real user.
        # homedir = pwd.getpwnam(self._user).pw_dir
        typo_dir = os.path.join(SEC_DB_PATH, user)
        self._db_path = os.path.join(typo_dir, DB_NAME + '.json')
        self._log_path = os.path.join(LOG_DIR, DB_NAME + '.log')
        # First thing first -- setting the logger object
        setup_logger(self._log_path, debug_mode, user)
        self.logger = logger  # just in case I need it
        logger.info("---UserTypoDB instantiated---")

        # creating dir only if it doesn't exist
        if not os.path.exists(typo_dir):
            try:
                os.makedirs(typo_dir)
                os.system(
                    "chgrp {1} {0} && chmod -R g+w {0} && chmod -R o-rw {0} {0}"
                    .format(typo_dir, GROUP))
            except OSError as error:
                logger.error(
                    "Trying to create: {}, but seems like the database"
                    " is not initialized.".format(typo_dir))
                raise UserTypoDB.NoneInitiatedDB(error)

        if not os.path.exists(self._db_path):
            with open(self._db_path, 'w') as dbf:
                json.dump({}, dbf)
            # cmd = 'chown root:{1} {0} && chmod o-rw {0};'.format(self._db_path, GROUP)
            change_db_ownership(self._db_path)

        try:
            self._db = json.load(open(self._db_path, 'r'))
        except (ValueError, IOError) as e:
            self._db = {}

        if auxT in self._db:
            self._aux_tab = self._db[auxT]
        else:
            self._aux_tab = self._db[auxT] = {}

        # always contains the serialized versin of sk, pk
        self._sk, self._pk = None, None
        # the global salt for the hmac-id only will be available if
        # correct pw is provided.
        self._hmac_salt, self._pw, self._pwent = None, '', -1
Пример #16
0
    def __init__(self, user, debug_mode=False):
        # type: (str, bool) -> None
        assert is_user(user), "User {!r} does not exists".format(user)

        # Disable Typtop for root
        # assert pwd.getpwnam(user).pw_uid != 0,\
        #     "Currently Typtop is disabled for {} user.".format(user)

        self._user = user  # this is a real user.
        # homedir = pwd.getpwnam(self._user).pw_dir
        typo_dir = os.path.join(SEC_DB_PATH, user)
        self._db_path = os.path.join(typo_dir, DB_NAME + '.json')
        self._log_path = os.path.join(LOG_DIR, DB_NAME + '.log')
        # First thing first -- setting the logger object
        setup_logger(self._log_path, debug_mode, user)
        self.logger = logger  # just in case I need it
        logger.info("---UserTypoDB instantiated---")

        # creating dir only if it doesn't exist
        if not os.path.exists(typo_dir):
            try:
                os.makedirs(typo_dir)
                os.system(
                    "chgrp {1} {0} && chmod -R g+w {0} && chmod -R o-rw {0} {0}".format(typo_dir, GROUP)
                )
            except OSError as error:
                logger.error("Trying to create: {}, but seems like the database"
                             " is not initialized.".format(typo_dir))
                raise UserTypoDB.NoneInitiatedDB(error)

        if not os.path.exists(self._db_path):
            with open(self._db_path, 'w') as dbf:
                json.dump({}, dbf)
            # cmd = 'chown root:{1} {0} && chmod o-rw {0};'.format(self._db_path, GROUP)
            change_db_ownership(self._db_path)

        try:
            self._db = json.load(open(self._db_path, 'r'))
        except (ValueError, IOError) as e:
            self._db = {}

        if auxT in self._db:
            self._aux_tab = self._db[auxT]
        else:
            self._aux_tab = self._db[auxT] = {}

        # always contains the serialized versin of sk, pk
        self._sk, self._pk = None, None
        # the global salt for the hmac-id only will be available if
        # correct pw is provided.
        self._hmac_salt, self._pw, self._pwent = None, '', -1
Пример #17
0
 def check(self, pw):
     logger.info("Checking entered password.")
     pk = self.get_pk()  # cannot be tampered
     typo_cache = self.get_from_auxtdb(TYPO_CACHE)  # , yaml.load)
     match_found = False
     freq_counts = []
     i = 0
     for i, sk_ctx in enumerate(typo_cache):
         try:
             sk = pwdecrypt(pw, sk_ctx)
             if not verify_pk_sk(pk,
                                 bytes(sk)):  # Somehow the hash matched !!
                 logger.error("pk-sk Verification failed!!")
                 continue
             self._sk = sk
         except (TypeError, ValueError) as e:  # Decryption Failed
             # print("Failed for {}.{} ({})".format(pw, i, e))
             # that means password did not match.
             continue
         header = yaml.safe_load(
             pkdecrypt(sk, self.get_from_auxtdb(HEADER_CTX)))
         self._hmac_salt = urlsafe_b64decode(header[HMAC_SALT])
         freq_counts = header[FREQ_COUNTS]
         if i > 0:
             freq_counts[i - 1] += 1
         self._pw = header[REAL_PW]
         self._pwent = entropy(self._pw)
         self.insert_log(pw, in_cache=True, ts=get_time())
         match_found = True
         break
     allowed = False
     if match_found:
         assert self._pwent >= 0, "PW is not initialized: {}".format(
             self._pwent)
         self._update_typo_cache_by_waitlist(typo_cache, freq_counts)
         if i == 0:  # the real password entered
             self.check_login_count(update=True)
             allowed = True
         else:  # A typo entered
             allowed = (self.check_login_count(update=False)
                        and self.is_allowed_login())
     else:
         self._add_typo_to_waitlist(pw)
         allowed = False
     logger.info("TypTop's decision: LoginAllowed = {}".format(allowed))
     return allowed
Пример #18
0
 def check(self, pw):
     logger.info("Checking entered password.")
     pk = self.get_pk()   # cannot be tampered
     typo_cache = self.get_from_auxtdb(TYPO_CACHE)  # , yaml.load)
     match_found = False
     freq_counts = []
     i = 0
     for i, sk_ctx in enumerate(typo_cache):
         try:
             sk = pwdecrypt(pw, sk_ctx)
             if not verify_pk_sk(pk, bytes(sk)):  # Somehow the hash matched !!
                 logger.error("pk-sk Verification failed!!")
                 continue
             self._sk = sk
         except (TypeError, ValueError) as e: # Decryption Failed
             # print("Failed for {}.{} ({})".format(pw, i, e))
             # that means password did not match.
             continue
         header = yaml.safe_load(
             pkdecrypt(sk, self.get_from_auxtdb(HEADER_CTX))
         )
         self._hmac_salt = urlsafe_b64decode(header[HMAC_SALT])
         freq_counts = header[FREQ_COUNTS]
         if i > 0:
             freq_counts[i-1] += 1
         self._pw = header[REAL_PW]
         self._pwent = entropy(self._pw)
         self.insert_log(pw, in_cache=True, ts=get_time())
         match_found = True
         break
     allowed = False
     if match_found:
         assert self._pwent >= 0, "PW is not initialized: {}".format(self._pwent)
         self._update_typo_cache_by_waitlist(typo_cache, freq_counts)
         if i == 0:   # the real password entered
             self.check_login_count(update=True)
             allowed = True
         else:   # A typo entered
             allowed = (self.check_login_count(update=False) and
                        self.is_allowed_login())
     else:
         self._add_typo_to_waitlist(pw)
         allowed = False
     logger.info("TypTop's decision: LoginAllowed = {}".format(allowed))
     return allowed
Пример #19
0
    def reinit_typtop(self, newPw):
        """
        Re-initiate the DB after a pw change.
        Most peripherial system settings don't change, including installID
        generates a new hmac salt,
        and encrypts the new pw, pw_ent, and the hmac salt
        """
        if not self.is_typtop_init():
            self.init_typtop(newPw)
        # Mostly a simple copy-paste of steps 1 to 2.5
        logger.info("Re-intializing after a pw change")
        # 1. derive public_key from the original password
        # 2. encrypt the global salt with the enc pk
        self._hmac_salt = os.urandom(16)  # global salt
        pk, sk = generate_key_pair()  # ECC key pair
        self._pk, self._sk = pk, serialize_sk(sk)
        self._pw = newPw
        perm_index = self._fill_cache_w_garbage()
        if WARM_UP_CACHE:
            freq_counts = range(CACHE_SIZE, 0, -1)
            for i, f in enumerate(range(CACHE_SIZE)):
                freq_counts[perm_index[i]] = freq_counts[i]
        else:
            freq_counts = [0 for _ in range(CACHE_SIZE)]

        header_ctx = pkencrypt(
            self._pk,
            json.dumps({
                REAL_PW: self._pw,
                HMAC_SALT: urlsafe_b64encode(self._hmac_salt),
                FREQ_COUNTS: freq_counts
            }))
        self.set_in_auxtdb(HEADER_CTX, header_ctx)
        self.set_in_auxtdb(ENC_PK, serialize_pk(self._pk))
        # 3 sending logs and deleting tables:
        logger.debug("Sending logs, deleting tables")

        # 4. Filling the Typocache with garbage
        self._fill_waitlist_w_garbage()
        self.set_status(SYSTEM_STATUS_ALL_GOOD)
        logger.info("RE-Initialization Complete")
Пример #20
0
    def reinit_typtop(self, newPw):
        """
        Re-initiate the DB after a pw change.
        Most peripherial system settings don't change, including installID
        generates a new hmac salt,
        and encrypts the new pw, pw_ent, and the hmac salt
        """
        if not self.is_typtop_init():
            self.init_typtop(newPw)
        # Mostly a simple copy-paste of steps 1 to 2.5
        logger.info("Re-intializing after a pw change")
        # 1. derive public_key from the original password
        # 2. encrypt the global salt with the enc pk
        self._hmac_salt = os.urandom(16) # global salt
        pk, sk = generate_key_pair()  # ECC key pair
        self._pk, self._sk = pk, serialize_sk(sk)
        self._pw = newPw
        perm_index = self._fill_cache_w_garbage()
        if WARM_UP_CACHE:
            freq_counts = range(CACHE_SIZE, 0, -1)
            for i, f in enumerate(range(CACHE_SIZE)):
                freq_counts[perm_index[i]] = freq_counts[i]
        else:
            freq_counts = [0 for _ in range(CACHE_SIZE)]

        header_ctx = pkencrypt(self._pk, json.dumps({
            REAL_PW: self._pw,
            HMAC_SALT: urlsafe_b64encode(self._hmac_salt),
            FREQ_COUNTS: freq_counts
        }))
        self.set_in_auxtdb(HEADER_CTX, header_ctx)
        self.set_in_auxtdb(ENC_PK, serialize_pk(self._pk))
        # 3 sending logs and deleting tables:
        logger.debug("Sending logs, deleting tables")

        # 4. Filling the Typocache with garbage
        self._fill_waitlist_w_garbage()
        self.set_status(SYSTEM_STATUS_ALL_GOOD)
        logger.info("RE-Initialization Complete")
Пример #21
0
    def _update_typo_cache_by_waitlist(self, typo_cache, freq_counts):
        """
        Updates the hash cache according to waitlist and clears the waitlist
        @typo_cache: a list of typos in the cache, and @freq_counts are the
        corresponding frequencies.

        returns: Updated typo_cache and their frequencies. Also applies the
        permutations.
        """
        logger.info("Updating TypoCache by Waitlist")
        good_typo_list = self._decrypt_n_filter_waitlist()
        mini, minf = min(enumerate(freq_counts), key=itemgetter(1))
        for typo, f in good_typo_list:
            if UserTypoDB.cache_insert_policy(minf, f):
                logger.debug("Inserting: {} @ {}".format(typo, mini))
                typo_cache[mini + 1] = pwencrypt(typo, self._sk)
                freq_counts[mini] = max(minf + 1, f)  # TODO: Check
                mini, minf = min(enumerate(freq_counts), key=itemgetter(1))
            else:
                logger.debug("I miss you: {} ({} <-> {})".format(
                    typo, minf, f))
                logger.debug("Freq counts: {}".format(freq_counts))

        # write the new typo_cache and freq_list
        # TODO: Apply permutation
        header_ctx = pkencrypt(
            self._pk,
            json.dumps({
                REAL_PW: self._pw,
                HMAC_SALT: urlsafe_b64encode(self._hmac_salt),
                FREQ_COUNTS: freq_counts
            }))
        logger.debug("Real pw={!r}".format(self._pw))

        self.set_in_auxtdb(HEADER_CTX, header_ctx)
        self.set_in_auxtdb(TYPO_CACHE, typo_cache)
        self.clear_waitlist()
Пример #22
0
def on_wrong_password(typo_db, password):
    logger.info("-\/-")
    is_match = False
    try:
        if not typo_db.is_typtop_init():
            logger.error("Typtop DB wasn't initiated yet!")
            # typo_db.init_typtop(password)
            return False
        check_system_status(typo_db)
        is_match = typo_db.check(password)
        # password has changed and this is an old password
        if is_match and typo_db.is_real_pw(password):
            logger.info("Password changed, old password entered. Re-initializing..")
            typo_db.reinit_typtop(urlsafe_b64encode(os.urandom(16)))
            return False
    except (ValueError, KeyError) as e:
        # probably  failure in decryption
        logger.exception("Error!! Probably failure in decryption. Re-initializing...")
        typo_db.reinit_typtop(password)
    except Exception as e:
        logger.exception("Unexpected error while on_wrong_password:\n{}\n"\
                         .format(e))
        print("TypToP is not initialized.\n $ sudo typtop --init")
    return is_match
Пример #23
0
 def clear_waitlist(self):
     self._fill_waitlist_w_garbage()
     logger.info("Waitlist is deleted.")
Пример #24
0
 def clear_waitlist(self):
     self._fill_waitlist_w_garbage()
     logger.info("Waitlist is deleted.")
Пример #25
0
    def init_typtop(self, pw, allow_typo_login=True):
        """Create the 'typtop' database in user's home-directory.  Changes

        Also, it initializes the required tables as well as the reuired
        variables, such as, the typo-cache size, the global salt etc.

        """
        logger.info("Initiating typtop db with {}".format(
            dict(allow_typo_login=allow_typo_login)))
        change_db_ownership(self._db_path)

        # db[auxT].delete()         # make sure there's no old unrelevent data
        # doesn't delete log because it will also be used
        # whenever a password is changed

        # *************** Initializing Aux Data *************************
        # *************** add org password, its' pks && global salt: ********
        # 1. derive public_key from the original password
        # 2. encrypt the global salt with the enc pk
        install_id = get_machine_id()
        install_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
        last_sent_time = get_time()
        self._hmac_salt = os.urandom(SALT_LENGTH)  # global salt
        self._pk, self._sk = generate_key_pair()  # ECC key pair
        self._sk = serialize_sk(self._sk)
        self._pw = pw
        self._aux_tab.update({
            INSTALLATION_ID: install_id,
            INSTALLATION_DATE: install_time,
            LOG_LAST_SENTTIME: last_sent_time,
            LOG_SENT_PERIOD: UPDATE_GAPS,
            SYSTEM_STATUS: SYSTEM_STATUS_NOT_INITIALIZED,
            LOGIN_COUNT: 0,
            ALLOWED_TYPO_LOGIN: allow_typo_login,
            ALLOWED_UPLOAD: True,
            ENC_PK: serialize_pk(self._pk),
            INDEX_J: random.randint(0, WAITLIST_SIZE - 1),
        })

        # Just get the ids of all possible typo candidates for warming
        # up the cache.
        perm_index = self._fill_cache_w_garbage()
        if WARM_UP_CACHE:
            freq_counts = range(CACHE_SIZE, 0, -1)
            for i in range(CACHE_SIZE):
                freq_counts[perm_index[i]] = freq_counts[i]
        else:
            freq_counts = [0 for _ in range(CACHE_SIZE)]
        header_ctx = pkencrypt(
            self._pk,
            json.dumps({
                REAL_PW: self._pw,
                HMAC_SALT: urlsafe_b64encode(self._hmac_salt),
                FREQ_COUNTS: freq_counts
            }))

        logger.info("Initializing the auxiliary data base ({})".format(auxT))
        self._aux_tab[HEADER_CTX] = header_ctx

        # self._aux_tab.create_index(['desc'])
        self.set_status(SYSTEM_STATUS_ALL_GOOD)
        # 3. Filling the Typocache with garbage
        self._fill_waitlist_w_garbage()
        logger.debug("Initialization Complete")
        isON = self.get_from_auxtdb(ALLOWED_TYPO_LOGIN)  # isON: boolean
        logger.info("typtop is ON? {}".format(isON))
Пример #26
0
    def init_typtop(self, pw, allow_typo_login=True):
        """Create the 'typtop' database in user's home-directory.  Changes

        Also, it initializes the required tables as well as the reuired
        variables, such as, the typo-cache size, the global salt etc.

        """
        logger.info("Initiating typtop db with {}".format(
            dict(allow_typo_login=allow_typo_login)
        ))
        change_db_ownership(self._db_path)

        # db[auxT].delete()         # make sure there's no old unrelevent data
        # doesn't delete log because it will also be used
        # whenever a password is changed

        # *************** Initializing Aux Data *************************
        # *************** add org password, its' pks && global salt: ********
        # 1. derive public_key from the original password
        # 2. encrypt the global salt with the enc pk
        install_id = get_machine_id()
        install_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
        last_sent_time = get_time()
        self._hmac_salt = os.urandom(SALT_LENGTH) # global salt
        self._pk, self._sk = generate_key_pair()  # ECC key pair
        self._sk = serialize_sk(self._sk)
        self._pw = pw
        self._aux_tab.update({
            INSTALLATION_ID: install_id,
            INSTALLATION_DATE: install_time,
            LOG_LAST_SENTTIME: last_sent_time,
            LOG_SENT_PERIOD: UPDATE_GAPS,
            SYSTEM_STATUS: SYSTEM_STATUS_NOT_INITIALIZED,
            LOGIN_COUNT: 0,
            ALLOWED_TYPO_LOGIN: allow_typo_login,
            ALLOWED_UPLOAD: True,
            ENC_PK: serialize_pk(self._pk),
            INDEX_J: random.randint(0, WAITLIST_SIZE-1),
        })

        # Just get the ids of all possible typo candidates for warming
        # up the cache.
        perm_index = self._fill_cache_w_garbage()
        if WARM_UP_CACHE:
            freq_counts = range(CACHE_SIZE, 0, -1)
            for i in range(CACHE_SIZE):
                freq_counts[perm_index[i]] = freq_counts[i]
        else:
            freq_counts = [0 for _ in range(CACHE_SIZE)]
        header_ctx = pkencrypt(self._pk, json.dumps({
            REAL_PW: self._pw,
            HMAC_SALT: urlsafe_b64encode(self._hmac_salt),
            FREQ_COUNTS: freq_counts
        }))

        logger.info("Initializing the auxiliary data base ({})".format(auxT))
        self._aux_tab[HEADER_CTX] = header_ctx

        # self._aux_tab.create_index(['desc'])
        self.set_status(SYSTEM_STATUS_ALL_GOOD)
        # 3. Filling the Typocache with garbage
        self._fill_waitlist_w_garbage()
        logger.debug("Initialization Complete")
        isON = self.get_from_auxtdb(ALLOWED_TYPO_LOGIN)   # isON: boolean
        logger.info("typtop is ON? {}".format(isON))