def _copy_pass(self, item, mgr): password = item["password"] srun(f"echo -n '{password}' | {self.copy_command['set']}", no_output=True) time.sleep(self.config['clipboard_timeout']) if srun(self.copy_command['get'])[1] == password: srun(self.copy_command['clear'], no_output=True)
def _do_log_in(self): exit_code, _ = srun("lpass status -q", no_output=True) if exit_code == 1: srun(f"lpass login --trust {self.pm_config['username']}") elif exit_code == 0: return else: raise Exception("Couldn't use LastPass, verify it's installed")
def set_session(self, session_key: str): """ Set the key holding the session hash """ if session_key: code, key_id = srun("keyctl padd user bw_session @u", stdin=session_key) if self.timeout > 0: if srun(f"keyctl timeout \"{int(key_id)}\" {self.timeout}")[0] != 0: raise Exception(f"Couldn't set timeout for key_id {int(key_id)}") elif self.timeout == 0: if srun("keyctl purge user bw_session")[0] != 0: raise Exception(f"Couldn't purge key_id {int(key_id)}")
def test_set_with_autolock(self): timeout = 3 session, _ = self.generate_session() mgr = BitwardenSession(auto_lock=True, timeout=timeout) srun("keyctl purge user bw_session &> /dev/null", no_output=True) mgr.set_session(session) time.sleep(timeout + 1) exit_code, _ = srun("keyctl request user bw_session") assert (exit_code != 0) # reset keyctl for other functions self.generate_session()
def get_session(self) -> str: """ Get the key holding the session hash """ code, stdout = srun("keyctl request user bw_session") if code != 0 or not stdout: code, passwd = rofi(prompt='Bitwarden Master Password', options=['password'], args={'lines': 0}) code, session_key = srun("bw unlock --raw", stdin=passwd) if code == 0: self.set_session(session_key) return session_key else: return srun(f"keyctl pipe {stdout}")[1]
def generate_session(self): """ Generates a new session_key :return: the session_key and the key_id for keyctl to find it """ srun("keyctl purge user bw_session &> /dev/null", no_output=True) exit_code, session_key = srun("bw unlock --raw", stdin=self.password) assert (exit_code == 0) assert (len(session_key) > 0) exit_code, key_id = srun("keyctl padd user bw_session @u", stdin=session_key) assert (exit_code == 0) return session_key, key_id
def test_fetch_items(self): mgr = BitwardenSession(auto_lock=False) session = mgr.get_session() resultcode, items_str = srun( f"bw list items --session '{session}' 2> /dev/null") items = json.loads(items_str) assert (len(items) > 0 and resultcode == 0)
def get_totp(self, item) -> str: if 'id' not in item: raise Exception("Can't get TOTP from invalid item") exit_code, result = srun(f"bw --session '{self.session}' get totp \"{item['id']}\"") if exit_code == 0: return result else: return ""
def _fetch_all_items(self) -> [dict]: """ Get the items list and filter for logins :return: list of all items """ item_str = srun(f"bw list items --session '{self.session}' 2>/dev/null")[1] return [self.parser.flat_map_item(item) for item in json.loads(item_str, encoding='utf-8') if item['type'] == item_types['LOGIN']]
def _fetch_all_items(self) -> [dict]: """ Lastpass supports exporting items into CSV :return: flat list of items converted into dict """ exit_code, items_csv = srun("lpass export --fields=id,name,fullname,username," "password,last_modified_gmt,last_touch,group,url,note") if exit_code != 0: raise Exception("Something went wrong retrieving Lastpass items") keys = items_csv.split('\n')[0] lines = items_csv.split('\n')[1:] items = [ {k: self.parser.flat_map_item(v) for k, v in zip(keys.split(','), line.split(','))} for line in lines ] return items
def sync(self): exit_code, _ = srun(f"bw sync --session '{self.session}' &> /dev/null", no_output=True) if exit_code == 0: self._items = self._fetch_all_items()
def _type_pass(self, item, mgr): time.sleep(0.2) password = item["password"] srun(f"xdotool type '{password}'") if self.config['danger_mode']: srun("xdotool key Return")
def _type_user(item, mgr): time.sleep(0.2) username = item["username"] srun(f"xdotool type '{username}'")
def _type_all(self, item, mgr): self._type_user(item, mgr) srun("xdotool key Tab") self._type_pass(item, mgr)
def _copy_totp(self, item, mgr): totp = mgr.get_totp(item) if len(totp) > 0: srun(f"echo -n '{totp}' | {self.copy_command['set']}", no_output=True)
def sync(self): exit_code, _ = srun("lpass sync", no_output=True) if exit_code == 0: self._items = self._fetch_all_items()