finished clipboard and QR functionality.
This commit is contained in:
parent
7b7d265592
commit
b3058348f1
@ -1,4 +1,5 @@
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import logging
|
||||
@ -21,6 +22,10 @@ except ImportError:
|
||||
|
||||
|
||||
def genQr(data, image = False):
|
||||
if isinstance(data, dict):
|
||||
data = json.dumps(dict, indent = 4)
|
||||
if not isinstance(data, str):
|
||||
data = str(data)
|
||||
_logger.debug('Generating QR code')
|
||||
qr = qrcode.QRCode(error_correction = qrcode.constants.ERROR_CORRECT_H)
|
||||
qr.add_data(data)
|
||||
|
@ -270,6 +270,7 @@ class VaultPass(object):
|
||||
print(data.read())
|
||||
data.seek(0, 0)
|
||||
# TODO: clip, etc.
|
||||
clipboard.pasteClipboard(printme = printme)
|
||||
return(data)
|
||||
|
||||
def initVault(self, *args, **kwargs):
|
||||
|
@ -413,12 +413,11 @@ def parseArgs():
|
||||
show.add_argument('-c', '--clip',
|
||||
nargs = '?',
|
||||
type = int,
|
||||
default = constants.SHOW_CLIP_LINENUM,
|
||||
default = None,
|
||||
metavar = 'LINE_NUMBER',
|
||||
dest = 'clip',
|
||||
help = ('If specified, copy line number LINE_NUMBER (Default: {0}) from the secret to the '
|
||||
'clipboard instead of printing it. '
|
||||
'Use 0 for LINE_NUMBER for the entire secret').format(constants.SHOW_CLIP_LINENUM))
|
||||
help = ('If specified, do not print the secret but instead copy it to the clipboard. '
|
||||
'LINE_NUMBER has no effect and is kept for compatibility reasons'))
|
||||
show.add_argument('-q', '--qrcode',
|
||||
dest = 'qr',
|
||||
nargs = '?',
|
||||
|
@ -1,2 +1,128 @@
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pwd
|
||||
import re
|
||||
# We COULD use pyperclip or pygtk or whatever for this, but we have enough external deps already.
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import warnings
|
||||
_logger = logging.getLogger()
|
||||
##
|
||||
import psutil
|
||||
##
|
||||
from . import constants
|
||||
|
||||
|
||||
def getProc(display, clipboard):
|
||||
real_uid = pwd.getpwnam(os.getlogin()).pw_uid
|
||||
procs = [] # Normally I'd do this in a list comprehension but switching to a loop for readability.
|
||||
for p in psutil.process_iter(attrs = ['name', 'cmdline', 'environ', 'uids']):
|
||||
if p.name() != 'xclip':
|
||||
continue
|
||||
if p.uids().effective == real_uid:
|
||||
p_display = p.environ().get('DISPLAY')
|
||||
cbrd = None
|
||||
for idx, arg in enumerate(p.cmdline()):
|
||||
if arg.startswith('-se'):
|
||||
cbrd = p.cmdline()[(idx + 1)]
|
||||
break
|
||||
if p_display == display and cbrd == clipboard:
|
||||
return(p)
|
||||
return(None)
|
||||
|
||||
|
||||
def pasteClipboard(data,
|
||||
seconds = constants.CLIP_TIMEOUT,
|
||||
clipboard = constants.CLIPBOARD,
|
||||
printme = False,
|
||||
*args, **kwargs):
|
||||
if clipboard not in constants.ALLOWED_CLIPBOARDS:
|
||||
_logger.error('Invalid clipboard name')
|
||||
_logger.debug(('The clipboard "{0}" is invalid. '
|
||||
'Must be one of: {1}.').format(', '.join((clipboard, constants.ALLOWED_CLIPBOARDS))))
|
||||
raise ValueError('Invalid clipboard')
|
||||
if isinstance(data, dict):
|
||||
data = json.dumps(dict, indent = 4)
|
||||
if not isinstance(data, str):
|
||||
data = str(data)
|
||||
_logger.debug('Copying to clipboard {0} for {1} seconds'.format(clipboard, seconds))
|
||||
termname = os.environ.get('TERM', 'linux')
|
||||
if termname == 'linux':
|
||||
# We don't have X, so we have no usable xclip.
|
||||
_logger.warning('Disabling clipboard copying because we don\'t have X')
|
||||
return(None)
|
||||
display = os.environ.get('DISPLAY')
|
||||
if not display:
|
||||
# We don't have X, so we have no usable xclip.
|
||||
_logger.warning('Disabling clipboard copying because we don\'t have X')
|
||||
return(None)
|
||||
exists = getProc(display)
|
||||
current = None
|
||||
if exists:
|
||||
cmd = subprocess.run(['xclip',
|
||||
'-out',
|
||||
'-display', display,
|
||||
'-selection', clipboard])
|
||||
current = cmd.stdout
|
||||
exists.kill()
|
||||
cmd = subprocess.run(['xclip',
|
||||
'-display', display,
|
||||
'-selection', clipboard],
|
||||
input = data.encode('utf-8'),
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE)
|
||||
if cmd.returncode != 0:
|
||||
_logger.error('Could not write to clipboard')
|
||||
_logger.debug('Could not write to clipboard "{0}" on display {1}.'.format(clipboard, display))
|
||||
for x in ('stdout', 'stderr'):
|
||||
i = getattr(cmd, x)
|
||||
if i:
|
||||
i = i.decode('utf-8').strip()
|
||||
if i != '':
|
||||
_logger.debug('{0}: {1}'.format(x.upper(), i))
|
||||
raise RuntimeError('Could not write to clipboard')
|
||||
if printme:
|
||||
print('Copied to clipboard "{0}".'.format(clipboard))
|
||||
if seconds is not None:
|
||||
if printme:
|
||||
print('Active for {0} seconds...'.format(seconds))
|
||||
for s in range(seconds, 0, -1):
|
||||
sys.stdout.write('{0} seconds remaining...'.format(s))
|
||||
sys.stdout.flush()
|
||||
time.sleep(1)
|
||||
sys.stdout.write('\r')
|
||||
print('\033[2KClipboard cleared.')
|
||||
else:
|
||||
for s in range(seconds, 0, -1):
|
||||
time.sleep(1)
|
||||
if current:
|
||||
cmd = subprocess.run(['xclip',
|
||||
'-display', display,
|
||||
'-selection', clipboard],
|
||||
input = current,
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE)
|
||||
if cmd.returncode != 0:
|
||||
_logger.warning('Could not restore clipboard')
|
||||
_logger.debug('Could not restore clipboard "{0}" on display {1}.'.format(clipboard, display))
|
||||
for x in ('stdout', 'stderr'):
|
||||
i = getattr(cmd, x)
|
||||
if i:
|
||||
i = i.decode('utf-8').strip()
|
||||
if i != '':
|
||||
_logger.debug('{0}: {1}'.format(x.upper(), i))
|
||||
# We absolutely should warn about this.
|
||||
warnings.warn('Could not restore clipboard; secret remains in clipboard!')
|
||||
else:
|
||||
proc = getProc(display, clipboard)
|
||||
if not proc:
|
||||
_logger.warning('Could not restore clipboard')
|
||||
_logger.debug('Could not restore clipboard "{0}" on display {1}.'.format(clipboard, display))
|
||||
# We absolutely should warn about this.
|
||||
warnings.warn('Could not restore clipboard; secret remains in clipboard!')
|
||||
else:
|
||||
proc.kill()
|
||||
return(None)
|
||||
|
@ -18,6 +18,8 @@ SHOW_CLIP_LINENUM = 1
|
||||
CLIP_TIMEOUT = 45
|
||||
SELECTED_PASS_CHARS = ALL_PASS_CHARS
|
||||
SELECTED_PASS_NOSYMBOL_CHARS = ALPHANUM_PASS_CHARS
|
||||
# xclip(1)
|
||||
ALLOWED_CLIPBOARDS = ('primary', 'secondary', 'clipboard')
|
||||
CLIPBOARD = 'clipboard'
|
||||
GENERATED_LENGTH = 25 # I personally would prefer 32, but Pass compatibility...
|
||||
EDITOR = 'vi' # vi is on ...every? single distro and UNIX/UNIX-like, to my knowledge.
|
||||
|
Reference in New Issue
Block a user