diff --git a/shell/qaskpass b/shell/qaskpass index d8c4553..d54e9b3 100755 --- a/shell/qaskpass +++ b/shell/qaskpass @@ -5,24 +5,12 @@ import hashlib import os import random import re +import string import sys import termios -import time import tty -__version__ = "20250310.a" - - -class getch: - def get(self): - fd = sys.stdin.fileno() - old_settings = termios.tcgetattr(fd) - try: - tty.setraw(sys.stdin.fileno()) - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) - return ch +__version__ = "20250311.a" class bc: @@ -41,6 +29,8 @@ class bc: C = "\033[96m" bold = "\033[1m" z = "\033[0m" + noblink = "\033[?25l" + blink = "\033[?25h" def disable(self): for x in "rgbcmyzkRGBCMY": @@ -56,8 +46,7 @@ class QAsk: self.c.disable() self.user_input = "" self.eq = "▁▂▃▄▅▆▇█▇▆▅▄▃▂" - self.limits = ((self.c.r, 2), (self.c.y, 4), (self.c.c, 8), (self.c.g, 14)) - self.ch = getch() + self.limits = ((self.c.r, 2), (self.c.y, 4), (self.c.B, 7), (self.c.c, 9), (self.c.g, 12), (self.c.G, 15)) def get_opts(self): parser = argparse.ArgumentParser( @@ -100,78 +89,102 @@ class QAsk: return score def animchar(self, pos): - colorpos = len(self.user_input) % self.opts.w + """Returns one character, based on pwscore or pw hash""" i = len(self.user_input) - pos - if i < 0 and self.opts.measure: - return self.c.r + " ▁ "[random.randint(0, 2)] - if pos == colorpos: - clr = self.c.C - else: - clr = self.c.r + if self.opts.measure: + if i < 0: + return self.c.r + " ▁ "[random.randint(0, 2)] + rheight = random.randint(-1, 1) + clr = self.limits[0][0] score = self.pwscore() for limit in self.limits: if score > limit[1] - 1 + 2 * random.random(): clr = limit[0] else: break - if self.opts.measure: - rheight = random.randint(-1, 1) - else: - rheight = random.randint(-4, 4) - if len(self.user_input) == 0: - rheight = 0 - return clr + self.eq[int(rheight + (i / self.opts.w)) % 14] + return clr + self.eq[int(rheight + (i / self.opts.w)) % 14] + + else: # no measure + if len(self.user_input) == 0: + rheight = random.randint(0, 1) + height = 0 + clr = self.limits[0][0] + else: + rheight = random.randint(-1, 1) + height = int(self.sha256[i * 2 % len(self.sha256)], 16) / 2 + clr = self.limits[int(self.sha256[(1 + i * 2) % len(self.sha256)], 16) % len(self.limits)][0] + + return clr + self.eq[int(rheight + height) % 14] def pquit(self, s="", e=0): + print(self.c.blink, file=sys.stderr, end="") print(self.c.z, file=sys.stderr) print(s, end="", file=sys.stdout if e == 0 else sys.stderr) sys.exit(e) - def ask(self): - # 3= ctrl-c, 13=enter - # 127 = backspace + def check_sha256(self): - dot = "•" - display = f"{dot*4} {dot*4}" + self.sha256 = hashlib.sha256(self.user_input.encode("utf-8")).hexdigest() + if self.opts.expect_sha256: + if self.sha256 == self.opts.expect_sha256: + self.dot_color = self.c.G + self.dot = "♥" + self.enter_exitcode = 0 + else: + self.enter_exitcode = 10 + + def get_chr(self): + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + + def ask(self): + + print(self.c.noblink, file=sys.stderr, end="") + self.dot = "•" if self.opts.title: print(f"{self.c.Y}{self.opts.title}{self.c.z}", file=sys.stderr) - enter_exitcode = 0 + while True: try: + self.enter_exitcode = 0 if self.opts.w > 0: - dot_color = self.c.m - dot = "•" - if self.opts.expect_sha256: - enter_exitcode = 10 - if hashlib.sha256(self.user_input.encode("utf-8")).hexdigest() == self.opts.expect_sha256: - dot_color = self.c.G - dot = "♥" - enter_exitcode = 0 - display = dot_color + f"{dot*4} " - for i in range(self.opts.w): - display += self.animchar(i) - display += dot_color + f" {dot*4}" + self.c.z - print("\r" + self.c.z + display + "\r" + self.c.k, file=sys.stderr, end="") + self.dot_color = self.c.m + self.dot = "•" + self.check_sha256() + display = "".join( + [ + f"\r{self.c.z}{self.dot_color}{self.dot*4} ", + *[self.animchar(i) for i in range(self.opts.w)], + f" {self.dot_color}{self.dot*4}{self.c.z}\r{self.c.k}", + ] + ) + print(display, file=sys.stderr, end="") sys.stderr.flush() - key = self.ch.get() - + key = self.get_chr() + # ~ print(f'-{key}{key}{key}{key}{key}///{ord(key)}///{len(key)}-',file=sys.stderr) if ord(key) == 3: # ctrl-c self.pquit(e=1) - if ord(key) == 13: # enter - self.pquit(self.user_input, e=enter_exitcode) - if ord(key) == 27: # esc (also starts control characters - key = self.ch.get() + elif ord(key) == 13: # enter + self.pquit(self.user_input, e=self.enter_exitcode) + elif ord(key) == 27: # esc (also starts control characters + key = self.get_chr() if ord(key) == 27: self.pquit(e=1) continue - if ord(key) == 127: # backspace + elif ord(key) == 127: # backspace self.user_input = self.user_input[0:-1] else: - self.user_input += key - # ~ print(f'-{key}-',file=sys.stderr) - # ~ print(f'-{ord(key)}-',file=sys.stderr) + if key in string.printable: + self.user_input += key except Exception as e: + raise (e) self.pquit(s=str(e), e=1)