libvirt_cloud/roles/toxcore/overlay/Linux/usr/local/src/gridfire/gridfire.py.bak

899 lines
34 KiB
Python
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
# https://github.com/reid-k/gridfire
from __future__ import unicode_literals, print_function
__program__ = "Gridfire"
__version__ = "v0.5+testforge"
__doc__ = """
Gridfire is inspired by gpggrid, a security tool included in
Tinfoil Hat Linux, intended to resist shoulder-surfing and keylogging.
For more information on the project, see the README file distributed with Gridfire.
Gridfire is named after a fictional superweapon in Iain M Banks' Culture novels.
See http://everything2.com/title/Gridfire for more.
RIP Iain M Banks (1954-02-16 to 2013-06-09)
usage: gridfire.py [-h] [-a TTYALERT] [-c] [-g] [-u] [-l] [-b] [-o] [-d] [-f]
[-p] [-w] [-m METHOD] [-n] [-v VERBOSITY]
[-S SINGLE] [-D DOUBLE] [-R REPEAT ]
[ -P POS] [-H HEADER] [-A ANSWER] [-O fd]
[STDIN COMMAND [STDIN ARGS ...]]
positional arguments:
STDIN COMMAND Arguments to run a subprocess wih the password in stdin.
optional arguments:
-h, --help show this help message and exit
-a TTYALERT, --ttyalert TTYALERT
Set the alert mode (none, beep or flash)
-c Force concealment of entered text.
-g, --grid Ignore other options and behave like gpggrid.
-u Allow uppercase letters [A-Z].
-l Allow lowercase letters [a-z].
-b Allow binary numbers [0-1].
-o Allow octal numbers [0-7].
-d Allow decimal numbers [0-9].
-f Allow hexadecimal numbers [0-9][a-f][A-F].
-p Allow punctuation.
-w Allow whitespace.
-m METHOD, --method METHOD
Specify indexing method (0-3, higher is more secure,
default=3)
-n Append N newlines on output.
-v VERBOSITY, --verbosity VERBOSITY
Specify verbosity (0-5, higher is verbose, default=3)
-S SINGLE, --single SINGLE
Arg to pass to a subprocess with -SINGLE=password.
-D DOUBLE, --double DOUBLE
Arg to pass to a subprocess with --DOUBLE=password.
-R, --repeat
Repeat the password with a newline to a subprocess.
-P POS, --pos POS Position to place the Arg to a subprocess with
--DOUBLE/SINGLE=password.
-H HEADER, --header HEADER
Header line as a prompt (default "").
-A ANSWER, --answer ANSWER
Skip the grid and give the answer (for testing only).
"""
#Learn more about Tinfoil Hat Linux:
#Homepage: http://tinfoilhat.shmoo.com/
#Wikipedia: https://en.wikipedia.org/wiki/Tinfoil_Hat_Linux
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#TODO: Decide whether or not implement method 4
#TODO: Fix row index for non-default charsets
import os
import sys
import signal
import curses
import locale
import string
import random
import argparse
import _curses
from io import StringIO
import subprocess
from time import sleep
PY3 = sys.version_info[0] == 3
VERBOSE = 3
#
# 0: stdin
# 1: stdout
# 2: stderr
iOUT_FD = sys.stdout
try:
from pinentry import PinEntry
except ImportError:
PinEntry = None
oPinEntry = None
try:
from dialog import Dialog
except ImportError:
Dialog = None
oDIALOG = None
oLAST_DIR = '/tmp/'
# Allow stderr for the caller to use
def debug(message):
if VERBOSE <= 4: return
sys.stdout.write('DEBUG: ' + repr(message) +'\n')
pass
def info(message):
if VERBOSE <= 3: return
sys.stdout.write('INFO: ' + repr(message) +'\n')
pass
def warn(message):
if VERBOSE <= 2: return
sys.stdout.write('WARN: ' + repr(message) +'\n')
pass
def error(message):
if VERBOSE <= 1: return
sys.stdout.write('ERROR: ' + message +'\n')
pass
class DummyContextManager:
def __enter__(self):
return self
def __exit__(self, *exc):
return False
#Helps curses play nice
locale.setlocale(locale.LC_ALL, '')
code = locale.getpreferredencoding()
##### Defaults & Initial variables #####
charsets = ''
min_x, min_y = 55, 17
upperchar = ''
lowerchar = ''
out = ''
hide_out = 0
newline = 1
def spaceout(s):
i=len(s)-1 #number of spaces to be inserted
while i >= 1:
s = s[:-i]+" "+s[-i:]
i -= 1
return s
def make_parser():
"""Argument parsing"""
global VERBOSE
parser = argparse.ArgumentParser(add_help=True)
parser.add_argument('-a', '--ttyalert', type=str, help='Set the alert mode (none, beep or flash)')
parser.add_argument('-c', help="Force concealment of entered text.", action="store_true")
parser.add_argument('-g', '--grid', help="Ignore other options and behave like gpggrid.", action="store_true")
#~ parser.add_argument('-u', dest='char_u', action='store_true')
parser.add_argument('-u', help="Allow uppercase letters [A-Z].", action="store_true")
parser.add_argument('-l', help="Allow lowercase letters [a-z].", action="store_true")
parser.add_argument('-b', help="Allow binary numbers [0-1].", action="store_true")
parser.add_argument('-o', help="Allow octal numbers [0-7].", action="store_true")
parser.add_argument('-d', help="Allow decimal numbers [0-9].", action="store_true")
parser.add_argument('-f', help="Allow hexadecimal numbers [0-9][a-f][A-F].", action="store_true")
parser.add_argument('-p', help="Allow punctuation.", action="store_true")
parser.add_argument('-w', help="Allow whitespace.", action="store_true")
parser.add_argument('-m', '--method', help='Specify indexing method (0-3, higher is more secure, default=3)', dest='method', type=int, default=3)
parser.add_argument('-n', help="Append newlines on output.", dest='newline', type=int, default=1)
parser.add_argument('-v', '--verbosity', help='Specify verbosity (0-5, higher is verbose, default=3)', type=int, default=3)
parser.add_argument('-S', '--single', help="Arg to pass to a subprocess with -SINGLE=password.", dest="single", default='')
parser.add_argument('-D', '--double', help="Arg to pass to a subprocess with --DOUBLE=password.", dest="double", default='')
parser.add_argument('-R', '--repeat', help="Repeat the password with a newline to a subprocess", action="store_true")
parser.add_argument('-P', '--pos', help="Position to place the Arg to a subprocess with --DOUBLE/SINGLE=password.", dest="pos", type=int, default=1)
parser.add_argument('-H', '--header', help="Header line as a prompt (default \"\").", dest="header", default='')
parser.add_argument('-A', '--answer', help="Skip the grid and give the answer (for testing only).", dest="answer", default='')
parser.add_argument('-O', '--output_fd', help="Output file descriptor to print the answer (default 1).", dest="output_fd", type=int, default=1)
parser.add_argument('sargs', help="Arguments to run a subprocess wih the password in stdin.", type=str, default='', nargs='*') # metavar='STDIN COMMAND',
return parser
def make_grid(args):
"""Define character sets"""
punct = spaceout(string.punctuation)
punct2 = punct[52:]
punct = punct[:52]
whitespace = spaceout(string.whitespace)
#Select character sets
#TODO: Can this be simplified? args['u'+'l'] or whatnot?
#use_uppercases = (-1 != charsets.find("u"))
use_uppercases = args['u']
use_lowercases = args['l']
use_bindigits = args['b']
use_octdigits = args['o']
use_decdigits = args['d']
use_hexdigits = args['f']
use_punct = args['p']
use_whitespace = args['w']
_setcount = args['u']+args['l']+args['b']+args['o']+args['d']+args['f']+args['p']+args['w']
#if use_uppercases+use_lowercases+use_bindigits+use_octdigits+use_decdigits+use_hexdigits+use_punct+use_whitespace == 0:
if _setcount == 0:
use_uppercases = 1
use_lowercases = 1
use_decdigits = 1
use_punct = 1
use_whitespace = 1
use_numbers = 0
numbers = ''
if use_bindigits+use_octdigits+use_decdigits+use_hexdigits: use_numbers = 1
if use_bindigits: numbers = '0 1'
if use_octdigits: numbers = spaceout(string.octdigits)
if use_decdigits: numbers = spaceout(string.digits)
if use_hexdigits: numbers = spaceout(string.hexdigits)
##### Build static grid #####
grid = []
if use_uppercases:
if PY3:
grid.append(spaceout(string.ascii_uppercase))
else:
grid.append(spaceout(string.uppercase))
if use_lowercases:
if PY3:
grid.append(spaceout(string.ascii_lowercase))
else:
grid.append(spaceout(string.lowercase))
if use_numbers: grid.append(numbers)
if use_punct:
grid.append(punct)
grid.append(punct2)
return (use_uppercases,
use_lowercases,
use_decdigits,
use_punct,
use_whitespace,
punct,
punct2,
whitespace,
numbers,
grid, )
##### Build user interface #####
usagebanner = "Choose from grid by typing letter pairs like eF or Dg"
#? not hasattr(sys, 'frozen') and
if Dialog is not None and os.path.isfile('/usr/bin/dialog'):
shortcuts = "4:Shell 5:FName 6:FContents 7:Delete 8:Show/Hide 9:Quit 0:Done"
else:
shortcuts = "7:Delete 8:Show/Hide 9:Quit 0:Done"
def total_rows(use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct):
return use_lowercases+use_uppercases+use_decdigits+use_whitespace+use_punct+use_punct+1
def iMain(lSysArgv):
global password, exit_code, VERBOSE, iOUT_FD, oDIALOG, oLAST_DIR
global min_x, min_y, upperchar, lowerchar, out, hide_out
global oLAST_DIR
padpos = 0
stdscr = None
password = ''
exit_code = -1
out = ''
upperchar = ''
lowerchar = ''
if PY3:
uppercase = string.ascii_uppercase
lowercase = string.ascii_lowercase
else:
uppercase = string.uppercase
lowercase = string.lowercase
# Check for required size before continuing
def check_size(stdscr):
(size_y,size_x) = stdscr.getmaxyx()
if ((size_x < min_x)|(size_y < min_y)):
error( __program__+" needs a "+str(min_x)+"x"+str(min_y)+" character area to function.\n")
error( "please adjust your terminal size and restart "+__program__+".")
sys.exit(1)
def pad_draw(stdscr, pad, ly, lx, hy, hx, use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct, header, title):
rv = __program__ +" "+ __version__
pad.addstr(0,0," "*(hx+1),curses.A_REVERSE)
pad.addstr(0,2,rv,curses.A_REVERSE)
pad.addstr(1,0," "*min_x)
#~ pad.addstr(0,40," ")
pad.addstr(0,40,lowerchar,curses.A_REVERSE)
pad.addstr(0,41,upperchar,curses.A_REVERSE)
pad.addstr(0,73,"SHOW")
if hide_out:
pad.addstr(0,73,"HIDE")
pad.addstr(1,0,header)
pad.addstr(2,0,">>")
pad.addstr(2,4," "*(len(out)+1))
disp_out = out
if hide_out:
disp_out = len(out)*"*"
pad.addstr(2,4,disp_out)
##Draw the grid
global gridrow
gridrow = 6
gridoffset = 4
#Grid Indexes
pad.addstr(gridrow-2,gridoffset,spaceout(col_index))
for t in range(0, total_rows(use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct)):
pad.addstr(gridrow+t,1,row_index[t])
t += 1
#Index selection highlighting
if len(upperchar):
stdscr.addstr(gridrow-2,4+spaceout(col_index).find(upperchar),upperchar,curses.A_REVERSE)
if len(lowerchar):
stdscr.addstr(gridrow+row_index.find(lowerchar),1,lowerchar,curses.A_REVERSE)
#Static grid elements
### New grid draw method ###
r = 0
for s in grid:
pad.addstr(gridrow,gridoffset,grid[r])
r += 1
gridrow += 1
if use_whitespace:
#Draw the whitespace row
pad.addstr(gridrow,gridoffset," :Space :Tab :Enter")
pad.addstr(gridrow,gridoffset,col_index[0])
pad.addstr(gridrow,9+gridoffset,col_index[1])
pad.addstr(gridrow,18+gridoffset,col_index[2])
#If the corresponding columns are selected, highlight them
if len(upperchar)&(upperchar==col_index[0]):
stdscr.addstr(gridrow,4+col_index.find(upperchar),upperchar,curses.A_REVERSE)
if len(upperchar)&(upperchar==col_index[1]):
stdscr.addstr(gridrow,11+col_index.find(upperchar),upperchar,curses.A_REVERSE)
if len(upperchar)&(upperchar==col_index[2]):
stdscr.addstr(gridrow,19+col_index.find(upperchar),upperchar,curses.A_REVERSE)
gridrow += 1
#Draw the 'done' line, and highlight column if selected
pad.addstr(gridrow,gridoffset," :Ignore")
pad.addstr(gridrow,gridoffset,col_index[0])
# pad.addstr(gridrow,9+gridoffset,col_index[1])
# pad.addstr(gridrow,18+gridoffset,col_index[2])
if len(upperchar)&(upperchar==col_index[0]):
stdscr.addstr(gridrow,4+spaceout(col_index).find(upperchar),upperchar,curses.A_REVERSE)
if len(upperchar)&(upperchar==col_index[1]):
stdscr.addstr(gridrow,10+spaceout(col_index).find(upperchar),upperchar,curses.A_REVERSE)
if len(upperchar)&(upperchar==col_index[2]):
stdscr.addstr(gridrow,17+spaceout(col_index).find(upperchar),upperchar,curses.A_REVERSE)
#Help banners
pad.addstr(14,0,title)
pad.addstr(15,0,usagebanner)
# (1+hx-len(shortcuts))*' '+
pad.addstr(16,0,shortcuts,curses.A_REVERSE)
pad.refresh(padpos, 0, ly, lx, hy, hx)
def main_draw(stdscr, pad, use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct, header, title):
(max_y, max_x,) = stdscr.getmaxyx()
pad_draw(stdscr, pad, 0, 0, (max_y-2), (max_x-1), use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct, header, title)
stdscr.move(max_y-1,0)
try:
curses.curs_set(0)
except:
pass
stdscr.refresh()
def cycle_index(cyclemethod=3): #Argument specifies method, default is 3
global col_index, row_index
if PY3:
uppercase = string.ascii_uppercase
lowercase = string.ascii_lowercase
else:
uppercase = string.uppercase
lowercase = string.lowercase
#Method 0: Ordered letters and numbers, no randomization
#This method has 1 possible state and provides no security.
#Included to allow gridfire's use to limit possible symbols entered.
#For example, hex digits only when entering a WEP key.
if cyclemethod==0:
col_index = uppercase
row_index = lowercase
#Method 1: Ordered letters, random offset (as with gpggrid)
#The math might differ from gpggrid
#This method has 676 or 26^2 possible states
if cyclemethod==1:
offset = random.randint(0,25)
col_index = uppercase[offset:]+uppercase[:offset]
offset = random.randint(0,25)
row_index = lowercase[offset:]+lowercase[:offset]
#Method 2: use random.shuffle() to shuffle one index in place
#This might not work very well, see module documentation on
#issues with small len(x) exceeding period of RNGs
# http://docs.python.org/2/library/random.html
##This method has:
##403,291,461,126,605,635,584,000,000
##or 26! possible states (403.3 septillion)
if cyclemethod==2:
col_index = uppercase
colcycle = list(uppercase)
random.shuffle(colcycle)
col_index = ''.join(colcycle)
row_index = col_index.lower()
#Method 3: use random.shuffle() to shuffle indices in place
#This might not work very well, see module documentation on
#issues with small len(x) exceeding period of RNGs
# http://docs.python.org/2/library/random.html
#This method has:
#162,644,002,617,632,464,507,038,883,409,628,607,021,056,000,000,000,000
##or 26!^2 possible states (162.6 sexdecillion).
if cyclemethod==3:
col_index = uppercase
colcycle = list(uppercase)
random.shuffle(colcycle)
col_index = ''.join(colcycle)
row_index = lowercase
rowcycle = list(lowercase)
random.shuffle(rowcycle)
row_index = ''.join(rowcycle)
#TODO: Implement method 4 (mixed cases in row/column indexes)
# (This would require redoing input handling to recognize same-case pairs)
#Method 4 would have:
#80,658,175,170,943,878,571,660,636,856,403,766,975,289,505,440,883,277,824,000,000,000,000
#or 52! possible states (80.6 Unvigintillion).
def quit_scr(leave_message = "", exit_status= 0):
global password, exit_code
stdscr.keypad(0)
curses.echo()
curses.nocbreak()
curses.endwin()
# print leave_message
password = leave_message
exit_code = exit_status
parser = make_parser()
args = vars(parser.parse_args(lSysArgv))
debug('args.keys() ' +repr(args.keys()))
VERBOSE = args['verbosity']
cyclemethod = args['method'] or 3
header = args['header'] or ''
answer = args['answer'] or ''
output_fd = args['output_fd'] or 1
sargs = args['sargs']
if output_fd != 1:
iOUT_FD = os.fdopen(int(output_fd), 'w')
info('DEBUG: sargs=' + repr(sargs))
(use_uppercases,
use_lowercases,
use_decdigits,
use_punct,
use_whitespace,
punct,
punct2,
whitespace,
numbers,
grid ) = make_grid(args)
if answer:
# for testing - bypass the grid and accept the answer
password = answer
exit_code = 0
else:
if not stdscr:
stdscr = curses.initscr()
curses.noecho()
curses.start_color()
try:
curses.use_default_colors()
except:
pass
stdscr.keypad(1)
for key, value in _curses.__dict__.items():
if key[0:4] == 'ACS_' or key in ('LINES', 'COLS'):
if key == 'LINES':
value = value - 3
setattr(curses, key, value)
curses.flushinp ()
check_size(stdscr)
pad = curses.newpad(100,100)
if args['ttyalert'] == 'beep':
curses.beep()
elif args['ttyalert'] == 'flash':
curses.flash()
##### MAIN LOOP: draw the interface and handle user input #####
cycle_index(cyclemethod) #Don't start the program with unrandomized indexes
# If this isn't done, the program initially shows nothing
main_draw(stdscr, pad, use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct, header, '')
_previous_sigcont_handler = None
while exit_code == -1:
if hasattr(sys.stderr, 'getvalue'):
title = sys.stderr.getvalue().strip()
sys.stderr.buf = ''
else:
title = ''
if title:
title = title.split('\n')[-1]
main_draw(stdscr, pad, use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct, header, title)
curses.noecho()
curses.cbreak()
sys.stderr.flush()
sys.stdout.flush()
if not _previous_sigcont_handler:
_previous_sigcont_handler = signal.getsignal(signal.SIGCONT)
try:
c = stdscr.getkey()
except:
quit_scr()
break
if c == '0':
quit_scr(out) #on 'Done', write output and exit
break
if c in ['', '9', chr(27)]: # Quit
quit_scr() #on 'Cancel', exit without writing output
break
if c == '8': # Hide
hide_out -= hide_out+hide_out
hide_out += 1
elif ((c == '7')&(len(out)>=1)) or ((c == 'KEY_BACKSPACE')&(len(out)>=1)):
out = out[:len(out)-1] # Delete
elif Dialog is not None and c == '6': # File Contents
# you will first need to save the tty modes with a call to def_prog_mode()
# and then call endwin() to end the curses mode. This will leave you in the
# original tty mode. To get back to curses once you are done, call
# reset_prog_mode() . This function returns the tty to the state stored by
# def_prog_mode(). Then do refresh(), and you are back to the curses mode.
_curses.def_prog_mode() ; _curses.endwin()
sBut, sCode = lDialogFselect(oLAST_DIR, height=10, width=50, help_button=False)
if sBut == 'ok':
sOut = sCode
else:
return
sBut = 'ok'; sCode = '='
if sOut and out:
sText = sOut # "New text at Beginning, Replace or End"
sBut, sCode = lDialogCode(sText)
if sBut != 'ok':
pass
elif sCode == '<':
out = sOut + ' ' + out
elif sCode == '>':
out = out + ' ' + sOut
elif sCode == '=':
out = sOut
elif sCode == '':
out = ''
# oDIALOG.msgbox("Bug Alert: If the screen goes black, suspend to shell with ^Z and then use fg to come back to Gridfire " +sCode, height=8, width=40)
main_draw(stdscr, pad, use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct, header, '')
_curses.reset_prog_mode()
stdscr.refresh()
elif Dialog is not None and c == '5': # File Name
# you will first need to save the tty modes with a call to def_prog_mode()
# and then call endwin() to end the curses mode. This will leave you in the
# original tty mode. To get back to curses once you are done, call
# reset_prog_mode() . This function returns the tty to the state stored by
# def_prog_mode(). Then do refresh(), and you are back to the curses mode.
_curses.def_prog_mode() ; _curses.endwin()
sOut = sDialogFget()
sBut = 'ok'; sCode = '='
if sOut and out:
sText = sOut # "New text at Beginning, Replace or End"
sBut, sCode = lDialogCode(sText)
if sBut != 'ok':
pass
elif sCode == '<':
out = sOut + ' ' + out
elif sCode == '>':
out = out + ' ' + sOut
elif sCode == '=':
out = sOut
elif sCode == '':
out = ''
# oDIALOG.msgbox("Bug Alert: If the screen goes black, suspend to shell with ^Z and then use fg to come back to Gridfire " +sCode, height=8, width=40)
main_draw(stdscr, pad, use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct, header, '')
_curses.reset_prog_mode()
stdscr.refresh()
elif Dialog is not None and c == '4': # Shell
if oDIALOG is None:
oDIALOG = Dialog()
sCode = '='
sOut = ''
yStdoutdata = yStderrdata = b''
# you will first need to save the tty modes with a call to def_prog_mode()
# and then call endwin() to end the curses mode. This will leave you in the
# original tty mode. To get back to curses once you are done, call
# reset_prog_mode() . This function returns the tty to the state stored by
# def_prog_mode(). Then do refresh(), and you are back to the curses mode.
_curses.def_prog_mode() ; _curses.endwin()
sCode, sAnswer = oDIALOG.inputbox("Run command (erase to cancel)",
init='')
if sCode == 'ok' and sAnswer:
try:
devnull = subprocess.DEVNULL
except AttributeError: # Python < 3.3
devnull_context = devnull = open(os.devnull, "wb")
else:
devnull_context = DummyContextManager()
with devnull_context:
p = subprocess.Popen(sAnswer,
stdout=subprocess.PIPE,
stderr=devnull, close_fds=True)
if True:
( yStdoutdata, yStderrdata ) = p.communicate()
retcode = p.returncode
oDIALOG.scrollbox(yStdoutdata.decode().strip(),
15,50)
else:
retcode = p.wait()
ystdoutdata = p.stdout.read()
# One could use title=... instead of text=... to put the text
# in the title bar.
oDIALOG.programbox(fd=p.stdout.fileno(),
text="Output of command: " +sAnswer)
# oDIALOG.msgbox("Bug Alert: If the screen goes black, suspend to shell with ^Z and then use fg to come back to Gridfire " +str(retcode), height=8, width=40)
if retcode == 0:
sOut = yStdoutdata.decode().strip()
sBut = 'ok'; sCode = '='
if sOut and out:
sText = sOut # "New text at Beginning, Replace or End"
sBut, sCode = lDialogCode(sText)
if sBut != 'ok':
pass
elif sCode == '<':
out = sOut + ' ' + out
elif sCode == '>':
out = out + ' ' + sOut
elif sCode == '=':
out = sOut
elif sCode == '':
out = ''
_curses.reset_prog_mode()
stdscr.refresh()
elif c == '3': # was Ignore
# now 'Ignore' is a keypair to fool keystroke counting
pass
elif PinEntry is not None and c == '2': # unused
if oPinEntry is None:
oPinEntry = PinEntry()
oPinEntry.run()
# unfinished
#handle row/column selections
elif (uppercase.find(c)+1):
upperchar = c
elif (row_index[:total_rows(use_lowercases, use_uppercases, use_decdigits, use_whitespace, use_punct)].find(c)+1):
lowerchar = c
#if selection completes a pair, find choice, add to output, reset selection
if len(upperchar)&len(lowerchar):
#if selected pair chooses 'Done' or 'Cancel'
if((upperchar==col_index[0])&(lowerchar==row_index[len(grid)+1])):
#on 'Ignore', do nothing
pass
# :Space :Tab :Enter
elif((upperchar==col_index[0])&(lowerchar==row_index[len(grid)])):
out += ' ' #on 'Space'
elif((upperchar==col_index[1])&(lowerchar==row_index[len(grid)])):
out += ' ' #on 'Tab'
elif((upperchar==col_index[2])&(lowerchar==row_index[len(grid)])):
out += '\n' #on 'Enter'
# elif((upperchar==col_index[2])&(lowerchar==row_index[len(grid)])):
# out = out[:len(out)-1] #on 'Delete'
else:
rowchoice = row_index.find(lowerchar)
if rowchoice < len(grid):
if (grid[rowchoice].find("A") == 0):
out += uppercase[col_index.find(upperchar)]
if (grid[rowchoice].find("a") == 0):
out += lowercase[col_index.find(upperchar)]
if (grid[rowchoice].find("0") == 0)&(spaceout(col_index).find(upperchar) < len(numbers)):
out += numbers[spaceout(col_index).find(upperchar)]
if (grid[rowchoice].find("!") == 0):
out += punct[spaceout(col_index).find(upperchar)]
if (grid[rowchoice].find("_") == 0)&(spaceout(col_index).find(upperchar) < len(punct2)):
out += punct2[spaceout(col_index).find(upperchar)]
upperchar = ''
lowerchar = ''
cycle_index(cyclemethod)
single = args['single'] or ''
double = args['double'] or ''
repeat = args['repeat'] or ''
if single:
thing = ['-'+single, password]
sStdIn = None
elif double:
thing = ['--'+double, password]
sStdIn = None
elif repeat:
thing = []
sStdIn = password +'\n' +password
else:
thing = []
sStdIn = password
if exit_code == 0 and sargs and password:
# sys.stderr.write('EXIT: ' + repr(password) + '\n')
if type(sargs) == str:
#? quote
largs = sargs.split(' ')
elif type(sargs) == list and len(sargs) == 1 and sargs[0].find(' ') > 0:
largs = sargs[0].strip().split()
elif type(sargs) == list and len(sargs) > 1:
largs = sargs
else:
raise RuntimeError('ERROR: not list or str type(sargs) ' + str(type(sargs) ))
if thing:
pos = args['pos']
if pos == -1:
largs.append(thing)
else:
largs.insert(pos, thing)
shell = False
executable = '' # largs[0] sargs = ' '.join(largs[1:])
(exit_code, password,) = lSubprocess(largs, shell, executable, sStdIn=sStdIn)
else:
debug('len(password)=%d' % len(password))
# del password, exit_code
stdscr = None
cycle_index(cyclemethod) #Don't start the program with unrandomized indexes
retval = [exit_code, password][:]
out = ''
exit_code = -1
return retval
# should be getpass.getpass compatible
def getpass(prompt="", stream=None, tty=None, main_args=None):
# what should stream be if curses should be a tty
if tty is not None:
pass
elif stream is not None:
tty = os.ttyname(stream.fileno())
elif 'GPG_TTY' in os.environ:
tty = os.environ['GPG_TTY']
else:
tty = os.ttyname(sys.stdin.fileno())
with open(tty, 'r') as fd:
assert fd.isatty(), "The input stream must be a tty: %r" % (tty,)
if not hasattr(sys, '_stderr'):
sys._stderr = sys.stderr
sys.stderr = StringIO()
password = ''
exit_code = -1
if main_args is None:
main_args = ['-H', prompt]
else:
main_args += ['-H', prompt]
try:
(exit_code, password,) = main(main_args)
info('EXIT: getpass ' + prompt +' ' + repr(password))
except KeyboardInterrupt:
info('EXIT: getpass KeyboardInterrupt')
if hasattr(sys, '_stderr'):
sys.stderr = sys._stderr
return password
def sDialogFget():
global oLAST_DIR
sBut, sCode = lDialogFselect(oLAST_DIR, height=10, width=50, help_button=False)
sOut = ''
if sBut == 'ok':
sFile = sCode
try:
with open( sFile, 'rt') as iFd:
sOut = iFd.read().strip()
except Exception as e:
# dunno
pass
else:
if os.path.isdir(sFile):
oLAST_DIR = sFile
else:
oLAST_DIR = os.path.dirname(sFile)
oLAST_DIR = oLAST_DIR + '/'
return sOut
def lDialogFselect(sLastDir=None, height=10, width=50, help_button=False, prompt=None):
global oDIALOG, oLAST_DIR
if oDIALOG is None:
oDIALOG = Dialog()
if not sLastDir:
sLastDir = oLAST_DIR
sBut, sCode = oDIALOG.fselect(sLastDir, height, width, help_button=False)
return (sBut, sCode,)
def lDialogCode(sText):
lChoices = [("<", "Begin - Add the text at the beginning"),
("=", "All - Replace all with the text"),
(">", "End - Add the text at the end")]
sCode = '='
sBut, sCode = oDIALOG.menu(sText, height=16, width=50,
choices=lChoices,
title="Replace the buffer with file contents",
help_button=False)
return (sBut, sCode,)
def lSubprocess(largs, shell=False, executable='', sStdIn=''):
env = os.environ.copy()
if 'PYTHONPATH' in env:
del env['PYTHONPATH']
debug('executable=' + repr(executable) +' largs=' + repr(largs) ) # + ' len(password)=%d' % len(password)
yStdoutData = stderrdata = ''
try:
oProcess = subprocess.Popen(largs,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
shell=shell)
sleep(3)
except Exception as e:
error('Popen executable=' + repr(executable) +' largs=' + repr(largs) + '\n' + str(e))
exit_code = 1
sStdOut = ''
else:
if sStdIn:
(yStdoutData, stderrdata,) = oProcess.communicate(sStdIn.encode())
else:
#? wait
(yStdoutData, stderrdata,) = oProcess.communicate()
#? oProcess.close()
if stderrdata:
sys.stderr.write(stderrdata.decode() + '\n')
exit_code = oProcess.returncode
sStdOut = yStdoutData.decode()
return (exit_code, sStdOut,)
def main():
sargs = sys.argv[1:]
if type(sargs) == list and len(sargs) == 1 and sargs[0].find(' ') > 0:
lSysArgv = sargs[0].strip().split()
else:
lSysArgv = sargs
# print('DEBUG: ' +repr(sys.argv[1:]) +' ' +repr(type(sys.argv[1:])))
if hasattr(sys, 'frozen') and hasattr(sys, '_MEIPASS'):
print('DEBUG: running in a PyInstaller bundle')
(exit_code, password,) = iMain(lSysArgv)
iOUT_FD.write(password+('\n'*newline))
password = ''
sys.stderr.flush()
return exit_code
if __name__ == '__main__':
sys.exit(main())