class Client: def __init__(self): self.config = Config() self.daemon = StaticDaemon() def color_print(self, input_color, mes): if input_color == 'r': fore = 31 elif input_color == 'g': fore = 32 elif input_color == 'b': fore = 36 elif input_color == 'y': fore = 33 else: fore = 37 input_color = "\x1B[%d;%dm" % (1, fore) return "%s%s\x1B[0m" % (input_color, mes) def color_keyword(self, value, keyword=""): split = re.split(keyword, value) result = "" for i in range(0, len(split) - 1): result += split[i] result += self.color_print('r', keyword) result += split[len(split) - 1] return result def add_space(self, value, length=0): value += " " * length return value def to_text(self, table, origin_table): line_number = len(origin_table) if line_number <= 1: return column_number = len(origin_table[0]) column_width = [0 for i in range(0, column_number)] for line in origin_table: for i in range(0, column_number): if column_width[i] < len(str(line[i])): column_width[i] = len(str(line[i])) for i in range(0, line_number): for j in range(0, column_number): print(self.add_space(str(table[i][j]), column_width[j] - len(str(origin_table[i][j]))) + "\t", end="") print("\n", end="") def print_password(self, passwords, keyword="", show_key=True): table = [] origin_table = [] if show_key: table.append(["Id", "Mark", "Password", "Version", "Intro", "URL"]) origin_table.append(["Id", "Mark", "Password", "Version", "Intro", "URL"]) for password in passwords: table.append( [password[0].id, self.color_keyword(password[0].mark, keyword), password[1], password[0].version, self.color_keyword(password[0].intro, keyword), self.color_keyword(password[0].url, keyword)]) origin_table.append( [password[0].id, password[0].mark, password[1], password[0].version, password[0].intro, password[0].url]) else: table.append(["Id", "Mark", "Version", "Intro", "URL"]) origin_table.append(["Id", "Mark", "Version", "Intro", "URL"]) for password in passwords: table.append([password[0].id, self.color_keyword(password[0].mark, keyword), password[0].version, self.color_keyword(password[0].intro, keyword), self.color_keyword(password[0].url, keyword)]) origin_table.append( [password[0].id, password[0].mark, password[0].version, password[0].intro, password[0].url]) self.to_text(table, origin_table) def do(self, args): if args.operate == "add" or args.operate == "a": password = Password() password.mark = str(args.mark) if args.url: password.url = str(args.url) if args.intro: password.intro = str(args.intro) if args.release: password.version = int(args.release) if args.length: password.length = int(args.length) if args.type: password.type = args.type if args.no_password or self.config.get("option", "add_without_mpw") == "1": self.daemon.add(password) return master_password = getpass.getpass("Please input your master password:"******"option", "mpw_check") == "1": if self.daemon.check_master_password(master_password) != 1: print("Master Password Error. Please check or set your master password.") return pw_id = self.daemon.add(password) result = self.daemon.get(master_password, [pw_id]) self.print_password(result) return if args.operate == "del" or args.operate == "d": self.daemon.remove(args.id) return if args.operate == "ls" or args.operate == "l": if not args.mark: keyword = "" else: keyword = args.mark passwords = self.daemon.search(keyword) passwords = self.daemon.get("", [value.id for value in passwords]) self.print_password(passwords, keyword, False) return if args.operate == "get" or args.operate == "g": master_password = getpass.getpass("Please input your master password:"******"option", "mpw_check") == "1": if self.daemon.check_master_password(master_password) != 1: print("Master Password Error. Please check or set your master password.") return if not args.mark: keyword = "" else: keyword = args.mark passwords = self.daemon.search(keyword) passwords = self.daemon.get(master_password, [value.id for value in passwords]) self.print_password(passwords, keyword, True) return if not args.operate: if args.set_master_password: master_password = getpass.getpass("Please input your master password:"******"Please retype your master password:"******"Password didn't match. Please try again.") return self.daemon.generate_master_password_check(master_password) return
class StaticDaemon(Singleton): def __init__(self): self.storage = Storage() self.config = Config() self.salt = self.config.get('option', 'salt') self.storage.load() self.database = self.storage.database self.password_type = PasswordType() def search(self, keyword=""): result = [] if keyword == "": for pid, password in self.database['passwords'].items(): if password.available and not password.special: result.append(password) return result for pid, password in self.database['passwords'].items(): if (re.search(keyword, password.mark) or re.search(keyword, password.intro)) \ and password.available and not password.special: result.append(password) return result def add(self, password): self.storage.lock.acquire() result = self.search(password.mark) version = 0 for ele in result: if version < ele.version: version = ele.version version += 1 password.version = version password.sync_code = "A" self.database['passwords_num'] += 1 password.id = self.database['passwords_num'] if password.length < 8 or password.length > 32: raise PasswordError("Password length illegal", "Password length should between 8 and 32.", password) self.database['passwords'][str(password.id)] = password self.storage.lock.release() self.storage.save() return password.id def remove(self, password_id): self.storage.lock.acquire() if str(password_id) in self.database['passwords'].keys(): self.database['passwords'][str(password_id)].available = False self.database['passwords'][str(password_id)].sync_code = "M" self.storage.save() def get(self, master_password, passwords_id): result = {} for pid in passwords_id: if str(pid) in self.database['passwords'].keys(): password = self.database['passwords'][str(pid)] if password.special or not password.available: continue key = self.calculate_key(master_password, password) result[password] = key def compare(x, y): x = x[0] y = y[0] if x.mark > y.mark: return 1 if x.mark < y.mark: return -1 if x.version > y.version: return 1 if x.version < y.version: return -1 return 0 return sorted(result.items(), key=cmp_to_key(compare)) def modify(self, master_password, password): self.storage.lock.acquire() password.sync_code = "M" if password.length < 4 or password.length > 32: raise PasswordError("Password length illegal", "Password length should between 4 and 32.", password) self.database['passwords'][str(password.id)].append(password) self.storage.lock.release() self.storage.save() def calculate_key(self, master_password, password): result = master_password + password.mark + str(password.version) + self.salt result = hashlib.sha512( (hashlib.sha512(result.encode('utf-8')).hexdigest() + "ImoutoPassword").encode("utf-8")).hexdigest() result = self.password_type.change(result, password.type, password.length) return result def check_master_password(self, master_password): check = None for id, password in self.database['passwords'].items(): if password.special and password.mark == "MasterPasswordCheck": check = password break if not check: return -1 if check.intro == self.calculate_key(master_password, check): return 1 else: return 0 def generate_master_password_check(self, master_password): self.storage.lock.acquire() pid = 0 password = Password() if self.check_master_password(master_password) != -1: for key,item in self.database['passwords'].items(): if item.special and item.mark == "MasterPasswordCheck": pid = item.id password.sync_code = "M" break else: self.database['passwords_num'] += 1 pid = self.database['passwords_num'] password.sync_code = "A" password.id = pid password.special = True password.mark = "MasterPasswordCheck" password.intro = self.calculate_key(master_password, password) self.database['passwords'][str(pid)] = password self.storage.save() self.storage.lock.release()