leave measure out for now
This commit is contained in:
234
shell/qaskpass
234
shell/qaskpass
@@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import curses
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
@@ -26,31 +25,6 @@ class getch:
|
|||||||
return ch
|
return ch
|
||||||
|
|
||||||
|
|
||||||
def get_opts():
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Colorful password dialog",
|
|
||||||
epilog="Dialog printed to stderr, user input echoed to stdout, i.e. input=$( qaskpass )",
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument("--title", "-t", action="store", default=None, help="Title for dialog")
|
|
||||||
parser.add_argument("-w", action="store", type=int, default=5, help="Width of display area. 0 to disable display.")
|
|
||||||
parser.add_argument("--no-color", action="store_true", default=False, help="Disable colors")
|
|
||||||
parser.add_argument(
|
|
||||||
"--expect-sha256",
|
|
||||||
action="store",
|
|
||||||
default=None,
|
|
||||||
help="Show green dots when string matches the sha256 sum. Note: strip newlines before calculating!. Exitcode = 10 if checksum does not match.",
|
|
||||||
)
|
|
||||||
parser.add_argument("--version", action="version", version="%(prog)s {version}".format(version=__version__))
|
|
||||||
args = parser.parse_args()
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def termsize():
|
|
||||||
rows, columns = os.popen("stty size", "r").read().split()
|
|
||||||
return (int(rows), int(columns))
|
|
||||||
|
|
||||||
|
|
||||||
class bc:
|
class bc:
|
||||||
m = "\033[35m"
|
m = "\033[35m"
|
||||||
b = "\033[34m"
|
b = "\033[34m"
|
||||||
@@ -74,97 +48,133 @@ class bc:
|
|||||||
setattr(self, "bold", "")
|
setattr(self, "bold", "")
|
||||||
|
|
||||||
|
|
||||||
def pwscore(s):
|
class QAsk:
|
||||||
score = len(s) / 8
|
def __init__(self):
|
||||||
simple = False
|
self.opts = self.get_opts()
|
||||||
if re.search("[A-Z]", s):
|
self.c = bc()
|
||||||
score *= 2
|
if self.opts.no_color:
|
||||||
simple = True
|
self.c.disable()
|
||||||
if re.search("[a-z]", s):
|
self.user_input = ""
|
||||||
score *= 1.5
|
self.eq = "▁▂▃▄▅▆▇█▇▆▅▄▃▂"
|
||||||
simple = True
|
self.limits = ((self.c.r, 2), (self.c.y, 4), (self.c.c, 8), (self.c.g, 14))
|
||||||
if re.search("[0-9]", s):
|
self.ch = getch()
|
||||||
score *= 1.5
|
|
||||||
simple = True
|
|
||||||
if not simple:
|
|
||||||
score *= 2
|
|
||||||
return score
|
|
||||||
|
|
||||||
|
def get_opts(self):
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Colorful password dialog",
|
||||||
|
epilog="Dialog printed to stderr, user input echoed to stdout, i.e. input=$( qaskpass )",
|
||||||
|
)
|
||||||
|
|
||||||
def animchar(i, pos, colorpos, width, c, user_input):
|
parser.add_argument("--title", "-t", action="store", default=None, help="Title for dialog")
|
||||||
if i < 0:
|
parser.add_argument(
|
||||||
return " "
|
"-w", action="store", type=int, default=5, help="Width of display area. 0 to disable display."
|
||||||
if pos == colorpos:
|
)
|
||||||
clr = c.C
|
parser.add_argument("--no-color", action="store_true", default=False, help="Disable colors")
|
||||||
else:
|
parser.add_argument("--measure", action="store_true", default=False, help="Also measure password goodness")
|
||||||
clr = c.r
|
parser.add_argument(
|
||||||
score = pwscore(user_input)
|
"--expect-sha256",
|
||||||
for limit in ((c.r, 2), (c.y, 4), (c.c, 8), (c.g, 14)):
|
action="store",
|
||||||
if score > limit[1] - 1 + 2 * random.random():
|
default=None,
|
||||||
clr = limit[0]
|
help="Show green dots when string matches the sha256 sum. Note: strip newlines before calculating!. Exitcode = 10 if checksum does not match.",
|
||||||
else:
|
)
|
||||||
break
|
parser.add_argument("--version", action="version", version="%(prog)s {version}".format(version=__version__))
|
||||||
|
args = parser.parse_args()
|
||||||
|
return args
|
||||||
|
|
||||||
return clr + "▁▂▃▄▅▆▇█▇▆▅▄▃▂"[int(random.randint(-1, 1) + (i / width)) % 14]
|
def pwscore(self):
|
||||||
|
if not self.opts.measure:
|
||||||
|
return random.randint(0, 18)
|
||||||
|
score = len(set(self.user_input)) / 5
|
||||||
|
simple = False
|
||||||
|
if re.search("[A-Z]", self.user_input):
|
||||||
|
score *= 2
|
||||||
|
simple = True
|
||||||
|
if re.search("[a-z]", self.user_input):
|
||||||
|
score *= 1.5
|
||||||
|
simple = True
|
||||||
|
if re.search("[0-9]", self.user_input):
|
||||||
|
score *= 1.5
|
||||||
|
simple = True
|
||||||
|
if not simple:
|
||||||
|
score *= 2
|
||||||
|
return score
|
||||||
|
|
||||||
|
def animchar(self, pos):
|
||||||
|
colorpos = len(self.user_input) % self.opts.w
|
||||||
|
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
|
||||||
|
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]
|
||||||
|
|
||||||
def pquit(s="", e=0, c=bc()):
|
def pquit(self, s="", e=0):
|
||||||
print(c.z, file=sys.stderr)
|
print(self.c.z, file=sys.stderr)
|
||||||
print(s, end="", file=sys.stdout if e == 0 else sys.stderr)
|
print(s, end="", file=sys.stdout if e == 0 else sys.stderr)
|
||||||
sys.exit(e)
|
sys.exit(e)
|
||||||
|
|
||||||
|
def ask(self):
|
||||||
|
# 3= ctrl-c, 13=enter
|
||||||
|
# 127 = backspace
|
||||||
|
|
||||||
|
dot = "•"
|
||||||
|
display = f"{dot*4} {dot*4}"
|
||||||
|
if self.opts.title:
|
||||||
|
print(f"{self.c.Y}{self.opts.title}{self.c.z}", file=sys.stderr)
|
||||||
|
enter_exitcode = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
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="")
|
||||||
|
sys.stderr.flush()
|
||||||
|
key = self.ch.get()
|
||||||
|
|
||||||
|
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()
|
||||||
|
if ord(key) == 27:
|
||||||
|
self.pquit(e=1)
|
||||||
|
continue
|
||||||
|
if 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)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.pquit(s=str(e), e=1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
q = QAsk()
|
||||||
opts = get_opts()
|
q.ask()
|
||||||
# 3= ctrl-c, 13=enter
|
|
||||||
# 127 = backspace
|
|
||||||
ch = getch()
|
|
||||||
user_input = ""
|
|
||||||
|
|
||||||
dot = "•"
|
|
||||||
display = f"{dot*4} {dot*4}"
|
|
||||||
c = bc()
|
|
||||||
if opts.no_color:
|
|
||||||
c.disable()
|
|
||||||
if opts.title:
|
|
||||||
print(f"{c.Y}{opts.title}{c.z}", file=sys.stderr)
|
|
||||||
enter_exitcode = 0
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
if opts.w > 0:
|
|
||||||
dot_color = c.m
|
|
||||||
dot = "•"
|
|
||||||
if opts.expect_sha256:
|
|
||||||
enter_exitcode = 10
|
|
||||||
if hashlib.sha256(user_input.encode("utf-8")).hexdigest() == opts.expect_sha256:
|
|
||||||
dot_color = c.G
|
|
||||||
dot = "♥"
|
|
||||||
enter_exitcode = 0
|
|
||||||
colorpos = len(user_input) % opts.w
|
|
||||||
display = dot_color + f"{dot*4} "
|
|
||||||
for i in range(opts.w):
|
|
||||||
display += animchar(len(user_input) - i, i, colorpos, opts.w, c, user_input)
|
|
||||||
display += dot_color + f" {dot*4}" + c.z
|
|
||||||
print("\r" + c.z + display + "\r" + c.k, file=sys.stderr, end="")
|
|
||||||
sys.stderr.flush()
|
|
||||||
key = ch.get()
|
|
||||||
|
|
||||||
if ord(key) == 3: # ctrl-c
|
|
||||||
pquit(e=1)
|
|
||||||
if ord(key) == 13: # enter
|
|
||||||
pquit(user_input, e=enter_exitcode)
|
|
||||||
if ord(key) == 27: # esc (also starts control characters
|
|
||||||
key = ch.get()
|
|
||||||
if ord(key) == 27:
|
|
||||||
pquit(e=1)
|
|
||||||
continue
|
|
||||||
if ord(key) == 127: # backspace
|
|
||||||
user_input = user_input[0:-1]
|
|
||||||
else:
|
|
||||||
user_input += key
|
|
||||||
# ~ print(f'-{key}-',file=sys.stderr)
|
|
||||||
# ~ print(f'-{ord(key)}-',file=sys.stderr)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
pquit(s=str(e), e=1)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user