finished clipboard and QR functionality.

This commit is contained in:
brent s. 2020-04-07 21:30:36 -04:00
parent 7b7d265592
commit b3058348f1
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
5 changed files with 137 additions and 4 deletions

View File

@ -1,4 +1,5 @@
import io import io
import json
import os import os
import subprocess import subprocess
import logging import logging
@ -21,6 +22,10 @@ except ImportError:




def genQr(data, image = False): 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') _logger.debug('Generating QR code')
qr = qrcode.QRCode(error_correction = qrcode.constants.ERROR_CORRECT_H) qr = qrcode.QRCode(error_correction = qrcode.constants.ERROR_CORRECT_H)
qr.add_data(data) qr.add_data(data)

View File

@ -270,6 +270,7 @@ class VaultPass(object):
print(data.read()) print(data.read())
data.seek(0, 0) data.seek(0, 0)
# TODO: clip, etc. # TODO: clip, etc.
clipboard.pasteClipboard(printme = printme)
return(data) return(data)


def initVault(self, *args, **kwargs): def initVault(self, *args, **kwargs):

View File

@ -413,12 +413,11 @@ def parseArgs():
show.add_argument('-c', '--clip', show.add_argument('-c', '--clip',
nargs = '?', nargs = '?',
type = int, type = int,
default = constants.SHOW_CLIP_LINENUM, default = None,
metavar = 'LINE_NUMBER', metavar = 'LINE_NUMBER',
dest = 'clip', dest = 'clip',
help = ('If specified, copy line number LINE_NUMBER (Default: {0}) from the secret to the ' help = ('If specified, do not print the secret but instead copy it to the clipboard. '
'clipboard instead of printing it. ' 'LINE_NUMBER has no effect and is kept for compatibility reasons'))
'Use 0 for LINE_NUMBER for the entire secret').format(constants.SHOW_CLIP_LINENUM))
show.add_argument('-q', '--qrcode', show.add_argument('-q', '--qrcode',
dest = 'qr', dest = 'qr',
nargs = '?', nargs = '?',

View File

@ -1,2 +1,128 @@
import base64
import json
import logging
import os 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 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)

View File

@ -18,6 +18,8 @@ SHOW_CLIP_LINENUM = 1
CLIP_TIMEOUT = 45 CLIP_TIMEOUT = 45
SELECTED_PASS_CHARS = ALL_PASS_CHARS SELECTED_PASS_CHARS = ALL_PASS_CHARS
SELECTED_PASS_NOSYMBOL_CHARS = ALPHANUM_PASS_CHARS SELECTED_PASS_NOSYMBOL_CHARS = ALPHANUM_PASS_CHARS
# xclip(1)
ALLOWED_CLIPBOARDS = ('primary', 'secondary', 'clipboard')
CLIPBOARD = 'clipboard' CLIPBOARD = 'clipboard'
GENERATED_LENGTH = 25 # I personally would prefer 32, but Pass compatibility... 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. EDITOR = 'vi' # vi is on ...every? single distro and UNIX/UNIX-like, to my knowledge.