finished clipboard and QR functionality.
This commit is contained in:
parent
7b7d265592
commit
b3058348f1
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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 = '?',
|
||||||
|
@ -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)
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user