pax_global_header00006660000000000000000000000064133413064230014511gustar00rootroot0000000000000052 comment=ae15ac08e60bff78afe61d40f92d74de63edae58 upass-0.3.0/000077500000000000000000000000001334130642300126445ustar00rootroot00000000000000upass-0.3.0/.gitignore000066400000000000000000000005661334130642300146430ustar00rootroot00000000000000*.py[cod] __pycache__ # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts var sdist develop-eggs .installed.cfg lib lib64 # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Mr Developer .mr.developer.cfg .project .pydevproject # Backup versions of files [Kw’s scheme] o.* # GitHub token file .pypt/gh-token upass-0.3.0/.pypt/000077500000000000000000000000001334130642300137165ustar00rootroot00000000000000upass-0.3.0/.pypt/AURvm/000077500000000000000000000000001334130642300147105ustar00rootroot00000000000000upass-0.3.0/.pypt/AURvm/aurvm_client.py000077500000000000000000000052641334130642300177640ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # AURvm client script # Usage: ./aurvm_client.py $PROJECT $AUR_PKGNAME $AUR_PKGNAME_GIT $version use_git[true|false] # Part of the Python Project Template. # Copyright © 2013-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import base64 import io import json import subprocess import sys try: _, project, aur_pkgname, aur_pkgname_git, version, use_git = sys.argv except ValueError: sys.stderr.write("Usage: ./aurvm_client.py $PROJECT $AUR_PKGANME $AUR_PKGNAME_GIT $version use_git[true|false]\n") sys.exit(1) use_git = True if use_git == 'true' else False if use_git: gitver = subprocess.check_output(r"git describe --long | sed -E 's/([^-]*-g)/r\1/;s/-/./g;s/^v//g'", shell=True) gitver = gitver.decode('utf-8').strip() else: gitver = None with io.open('PKGBUILD', 'r', encoding='utf-8') as fh: pkgbuild = fh.read() data = json.dumps({ 'project': project, 'aur_pkgname': aur_pkgname, 'aur_pkgname_git': aur_pkgname_git, 'version': version, 'use_git': use_git, 'gitver': gitver, 'pkgbuild': pkgbuild, '_api': '2' }, ensure_ascii=True, sort_keys=True).encode('utf-8') print(base64.b64encode(data).decode('utf-8')) upass-0.3.0/.pypt/LICENSE.PyPT000066400000000000000000000043061334130642300155610ustar00rootroot00000000000000Python Project Template is licensed under a BSD-like license. You are free to relicense your code to another open source license. If you want to apply a commercial (a.k.a. proprietary) license, you must contact me first. HOWEVER, the following files must remain under the BSD license: * /.pypt/commitlog * /.pypt/ghrel * /.pypt/localegen * /.pypt/PYPT-UPDATE * /.pypt/README.rst * /.pypt/LICENSE.PyPT * /docs/CONTRIBUTING.rst * /CONTRIBUTING.rst * /release The README file for PyPT MAY NOT be relicensed. The actual license is: (the name may have been replaced by yours if you did the Getting up to speed in 16 easy steps, it was mine originally, and the version in .pypt/ should reflect that.) LICENSE ------- Copyright © 2013-2018, Chris Warrick. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author of this software nor the names of contributors to this software may be used to endorse or promote products derived from this software without specific prior written consent. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. upass-0.3.0/.pypt/aurvm_client.py000077500000000000000000000051761334130642300167740ustar00rootroot00000000000000#!/usr/bin/env python # AURvm client script # Usage: ./aurvm_client.py $PROJECT $AUR_PKGNAME $AUR_PKGNAME_GIT $version use_git[true|false] # Part of the Python Project Template. # Copyright © 2013-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import base64 import io import json import subprocess import sys try: _, project, aur_pkgname, aur_pkgname_git, version, use_git = sys.argv except ValueError: print("Usage: ./aurvm_client.py $PROJECT $AUR_PKGANME $AUR_PKGNAME_GIT $version use_git[true|false]") use_git = True if use_git == 'true' else False if use_git: gitver = subprocess.check_output(r"git describe --long | sed -E 's/([^-]*-g)/r\1/;s/-/./g;s/^v//g'", shell=True) gitver = gitver.decode('utf-8').strip() else: gitver = None with io.open('PKGBUILD', 'r', encoding='utf-8') as fh: pkgbuild = fh.read() data = json.dumps({ 'project': project, 'aur_pkgname': aur_pkgname, 'aur_pkgname_git': aur_pkgname_git, 'version': version, 'use_git': use_git, 'gitver': gitver, 'pkgbuild': pkgbuild, '_api': '2' }, ensure_ascii=True, sort_keys=True).encode('utf-8') print(base64.b64encode(data).decode('utf-8')) upass-0.3.0/.pypt/aurvm_heartbeat.sh000077500000000000000000000000321334130642300174210ustar00rootroot00000000000000#!/bin/sh echo "AURvm OK" upass-0.3.0/.pypt/aurvm_host.py000077500000000000000000000056541334130642300164740ustar00rootroot00000000000000#!/usr/bin/env python3 # AURvm host script # Usage: base64-encoded JSON on stdin # Part of the Python Project Template. # Copyright © 2013-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import base64 import io import json import os import subprocess import sys BASEDIR = os.path.expanduser('~/git/aur-pkgbuilds') def commitaur(msg): with open('.SRCINFO', 'wb') as fh: fh.write(subprocess.check_output(['makepkg', '--printsrcinfo'])) subprocess.check_call(['git', 'add', '.']) subprocess.check_call(['git', 'commit', '-asm', msg]) subprocess.check_call(['git', 'push', '-u', 'origin', 'master']) data = base64.b64decode(sys.stdin.read().encode('utf-8')) data = json.loads(data.decode('utf-8')) if data['_api'] != 2: print("API version does not match") msg = data['project'] + ' v' + data['version'] sys.stderr.write("[host] Updating AUR packages...\n") sys.stderr.flush() os.chdir(BASEDIR) os.chdir(data['aur_pkgname']) with io.open('PKGBUILD', 'w', encoding='utf-8') as fh: fh.write(data['pkgbuild']) commitaur(msg) os.chdir(BASEDIR) if data['use_git']: os.chdir(data['aur_pkgname_git']) subprocess.check_call(["sed", "s/pkgver=.*/pkgver=" + data['gitver'] + "/", "PKGBUILD", "-i"]) commitaur(msg) os.chdir(BASEDIR) subprocess.check_call(['./UPDATE-REQUIREMENTS.py']) subprocess.check_call(['git', 'commit', '-asm', msg]) subprocess.check_call(['git', 'push']) sys.stderr.write("[host] Done!\n") sys.stderr.flush() upass-0.3.0/.pypt/commitlog000077500000000000000000000107671334130642300156510ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Kw’s Release Tools/Python Project Template # Commit and Changelog Parser # Copyright © 2013-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ Parse commits and changelogs for PyPT. Usage: .pypt/commitlog FILE BASEDIR NEWVERSION, where FILE is the path to the CMFN file to parse, BASEDIR is the project directory, NEWVERSION is the new version number. All paths should be absolute. """ import argparse import re import sys from os.path import join as pjoin # Stolen from textwrap in Python 3.4.3 with PEP257 fixes def indent(text, prefix, predicate=None): """Add 'prefix' to the beginning of selected lines in 'text'. If 'predicate' is provided, 'prefix' will only be added to the lines where 'predicate(line)' is True. If 'predicate' is not provided, it will default to adding 'prefix' to all non-empty lines that do not consist solely of whitespace characters. """ if predicate is None: def predicate(line): return line.strip() def prefixed_lines(): for line in text.splitlines(True): yield (prefix + line if predicate(line) else line) return ''.join(prefixed_lines()) def main(): """commitlog main function.""" parser = argparse.ArgumentParser( description="Commit and Changelog Parser " "(part of Chris Warrick's Python Project Template)") parser.add_argument('filename', metavar='FILE', nargs=1, help='File to parse') parser.add_argument('basedir', metavar='BASEDIR', nargs=1, help='Project directory') parser.add_argument('new_version', metavar='NEWVERSION', nargs=1, help='New version (X.Y.Z)') args = parser.parse_args() # nargs gets you lists, not strings filename = args.filename[0] basedir = args.basedir[0] new_version = args.new_version[0] with open(filename) as fh: e = re.findall('#~ (C[A-Z]+) MESSAGE START ~#\n(.*?)\n#~ (C[A-Z]+) MESSAGE ' 'END ~#', fh.read(), flags=re.S) for i in e: i = list(i) if i[0] != i[2]: print('ERROR: mismatched tags') return 1 else: if i[0] == 'COMMIT': with open(filename + '-commit', 'w') as fh: fh.write(i[1]) elif i[0] == 'CHANGELOG': with open(pjoin(basedir, 'docs', 'CHANGELOG.rst')) as fh: currentfile = fh.read() # A bit fragile... currentver = re.search(':Version: (.*)', currentfile).groups()[0] clog = indent(i[1], 4 * ' ') with open(pjoin(basedir, 'docs', 'CHANGELOG.rst'), 'w') as fh: fh.write(currentfile.replace( '\n' + currentver, '\n{0}\n{1}\n\n{2}'.format( new_version, clog, currentver))) if __name__ == '__main__': sys.exit(main()) upass-0.3.0/.pypt/config000066400000000000000000000017361334130642300151150ustar00rootroot00000000000000#!/bin/bash # Human-friendly project name. PROJECT="upass" # Computer-friendly project name, [a-z0-9_\-] PROJECTLC="upass" # GitHub username. GITUSER="Kwpolska" # Git repository name. Using $PROJECTLC is recommended. GITREPO=$PROJECTLC # Locale type. One of: # none Do not generate nor use any locales. # gettext Use GNU gettext (gettext module). # gettext-tx Use GNU gettext (gettext module) and send to Transifex. # pyqt4 Use the Qt locale tools (stock Qt + PyQt4). # pyqt4-tx Use the Qt locale tools (stock Qt + PyQt4) and send to Transifex. # pyside Use the Qt locale tools (stock Qt + PySide). # pyside-tx Use the Qt locale tools (stock Qt + PySide) and send to Transifex. LOCALETYPE="none" # Python versions supported. PYTHON2=1 PYTHON3=1 # AUR package names. You still need to change PKGBUILDs! AUR_PKGNAME=$PROJECTLC AUR_PKGNAME_GIT=$PROJECTLC"-git" # Whether or not to create AUR -git packages. (true/false) AUR_GIT_PACKAGE="true" upass-0.3.0/.pypt/ghrel000077500000000000000000000100521334130642300147430ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Kw’s Release Tools/Python Project Template # GitHub Release Creator # Copyright © 2013-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ Create GitHub releases out of changelogs. Usage: .pypt/commitlog FILE BASEDIR REPOSITORY TAG, where FILE is the path to the file to use, which can be a plain .md file or a CMFN file, BASEDIR is the project directory, REPOSITORY is the full GitHub repository name (user/repo), TAG is the tag to write to. All paths should be absolute. """ import argparse import json import re import requests import sys from os.path import join as pjoin def main(): """ghrel main function.""" parser = argparse.ArgumentParser( description="GitHub Release Creator " "(part of Chris Warrick's Python Project Template)") parser.add_argument('filename', metavar='FILE', nargs=1, help='File to parse (Markdown or commitlog)') parser.add_argument('basedir', metavar='BASEDIR', nargs=1, help='Project directory (must contain .pypt/gh-token)') parser.add_argument('repo', metavar='REPOSITORY', nargs=1, help='GitHub repository (owner/repo)') parser.add_argument('tag', metavar='TAG', nargs=1, help='Tag to create release for (vX.Y.Z)') args = parser.parse_args() # nargs gets you lists, not strings filename = args.filename[0] basedir = args.basedir[0] repo = args.repo[0] tag = args.tag[0] with open(pjoin(basedir, '.pypt', 'gh-token')) as fh: token = fh.read().strip() headers = { 'User-Agent': 'Kwpolska/python-project-template', 'Authorization': 'token ' + token, } with open(filename) as fh: fdata = fh.read() e = re.findall( '#~ CHANGELOG MESSAGE START ~#\n(.*?)\n' '#~ CHANGELOG MESSAGE END ~#', fdata, flags=re.S) if e: # parse as a CMFN file, replace backticks (reST -> Markdown) message = e[0].replace('``', '`') else: # parse as a plain Markdown file message = fdata r = requests.post( 'https://api.github.com/repos/{0}/releases'.format(repo), data=json.dumps({'tag_name': tag, 'body': message}), headers=headers) if r.status_code == 201: print("GitHub Release created: {0}".format(r.json()['html_url'])) else: print("GitHub Release failed: {0}".format(r.text)) return 1 if __name__ == '__main__': sys.exit(main()) upass-0.3.0/.pypt/hooks/000077500000000000000000000000001334130642300150415ustar00rootroot00000000000000upass-0.3.0/.pypt/hooks/post-release.hook000066400000000000000000000025721334130642300203340ustar00rootroot00000000000000#!/bin/zsh . .pypt/config # To change default, move the ` || "$rln" == ""` condition wherever you desire # and change the capital letter in the prompt echo -n "Update AUR packages? [Remotely/locally/no] " read rln if [[ "$rln" == "N" || "$rln" == "n" ]]; then exit 0 fi if [[ "$rln" == "L" || "$rln" == "l" ]]; then echo "Updating AUR packages..." gitver=$(git describe --long | sed -E 's/([^-]*-g)/r\1/;s/-/./g;s/^v//g') cp PKGBUILD ~/git/aur-pkgbuilds/$AUR_PKGNAME/PKGBUILD cd ~/git/aur-pkgbuilds . ~/git/aur-pkgbuilds/aur.zsh cd $AUR_PKGNAME commitaur "$PROJECT v$version" if [[ "$AUR_GIT_PACKAGE" == "true" ]]; then cd $AUR_PKGNAME_GIT sed "s/pkgver=.*/pkgver=$gitver/" PKGBUILD -i commitaur "$PROJECT v$version" fi ./UPDATE-REQUIREMENTS.py git commit -asm "$PROJECT v$version" git push echo "Done!" fi if [[ "$rln" == "R" || "$rln" == "r" || "$rln" == "" ]]; then avout="" echo "[local] Attempting to remote into Arch Linux VM (ssh arch)..." while [[ "$avout" != "AURvm OK" ]]; do echo "[local] Sending heartbeat..." avout=$(ssh arch git/aur-pkgbuilds/aurvm_heartbeat.sh) done echo "[local] Sending data..." .pypt/AURvm/aurvm_client.py $PROJECT $AUR_PKGNAME $AUR_PKGNAME_GIT $version $AUR_GIT_PACKAGE | ssh arch git/aur-pkgbuilds/aurvm_host.py echo "[local] Done!" fi upass-0.3.0/.pypt/hooks/pre-sdist.hook000066400000000000000000000000321334130642300176300ustar00rootroot00000000000000#!/bin/zsh . .pypt/config upass-0.3.0/.pypt/localegen000077500000000000000000000125301334130642300155760ustar00rootroot00000000000000#!/bin/zsh # Kw’s Release Tools/Python Project Template # Locale Generator # Copyright © 2013-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. . .pypt/config case "$LOCALETYPE" in 'gettext' | 'gettext-tx') version=$(cat setup.py | grep 'version=' | sed -e 's/.*version=.//g' -e 's/.,$//g') date=$(date '+%Y-%m-%d') datel=$(date '+%Y-%m-%d %H:%M%z') datep=$(date '+%Y%m%d') xgettext -c ./$PROJECTLC/**/*.py localeprovider.py -o ./messages.pot sed '1,+17d' ./messages.pot > ./messages.pot.tmp pot='# '$PROJECT' pot file. # Copyright © 2018, Chris Warrick. # This file is distributed under the same license as the '$PROJECT' package. # Chris Warrick , 2016. # msgid "" msgstr "" "Project-Id-Version: #version\\n" "Report-Msgid-Bugs-To: Chris Warrick \\n" "POT-Creation-Date: #datel\\n" "PO-Revision-Date: #datel\\n" "Last-Translator: Chris Warrick \\n" "Language-Team: Chris Warrick \\n" "Language: en\\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=UTF-8\\n" "Content-Transfer-Encoding: 8bit\\n"' echo $pot > messages.pot cat ./messages.pot.tmp >> messages.pot rm ./messages.pot.tmp sed "s/#version/$version/g" messages.pot -i sed "s/#datel/$datel/g" messages.pot -i if [[ "$LOCALETYPE" == "gettext-tx" ]]; then tx push -s tx pull fi for i in ./locale/*; do language=$(basename $i) podir="./locale/$language/LC_MESSAGES" popath="./locale/$language/LC_MESSAGES/$PROJECTLC.po" sed 's/\"Project-Id-Version: .*/\"Project-Id-Version: '$version'\\n\"/' $popath -i msgmerge $popath messages.pot -o $popath fuzzy=$(cat $popath | grep -c '#, fuzzy') empty=$(cat $popath | pcregrep -cM 'msgstr ""\n$') if [ $fuzzy != '0' ]; then echo "WARNING: $fuzzy fuzzy strings in language $language." fi if [ $empty != '0' ]; then echo "WARNING: $empty empty strings in language $language." fi msgfmt -o $podir/$PROJECTLC.mo $popath done ;; 'pyqt4' | 'pyqt4-tx') pylupdate4 -verbose $PROJECTLC.pro if [[ "$LOCALETYPE" == "pyqt4-tx" ]]; then tx push -s tx pull fi for i in ./locale/*.ts; do # pylupdate4 is dumb and mangles encodings sed -i -e 's|filename="|filename="../|g' -e \ 's|“|“|g' -e 's|”|”|g' -e \ 's|‘|‘|g' -e 's|’|’|g' -e \ 's|…|…|g' -e 's|–|–|g' -e \ 's|—|—|g' $i done lrelease $PROJECTLC.pro pyrcc4 -py2 $PROJECTLC.qrc -o $PROJECTLC/ui/resources2.py pyrcc4 -py3 $PROJECTLC.qrc -o $PROJECTLC/ui/resources3.py ;; 'pyside' | 'pyside-tx') pyside-lupdate -verbose $PROJECTLC.pro if [[ "$LOCALETYPE" == "pyside-tx" ]]; then tx push -s tx pull fi for i in ./locale/*.ts; do # pyside may be dumb, too sed -i -e 's|filename="|filename="../|g' -e \ 's|“|“|g' -e 's|”|”|g' -e \ 's|‘|‘|g' -e 's|’|’|g' -e \ 's|…|…|g' -e 's|–|–|g' -e \ 's|—|—|g' $i done lrelease $PROJECTLC.pro pyside-rcc -py2 $PROJECTLC.qrc -o $PROJECTLC/ui/resources2.py pyside-rcc -py3 $PROJECTLC.qrc -o $PROJECTLC/ui/resources3.py ;; 'none') true ;; *) echo 'ERROR: unknown locale type.'; false esac upass-0.3.0/.travis.yml000066400000000000000000000005451334130642300147610ustar00rootroot00000000000000language: python sudo: false python: - "2.7" - "3.3" - "3.4" - "pypy" install: - "pip install -r requirements.txt" - "pip install pytest coverage pytest-cov" - "pip install ." script: - "py.test --cov upass --cov-report term-missing tests/" notifications: email: on_success: always # use "change" to get less emails on_failure: always upass-0.3.0/AUTHORS000066400000000000000000000001231334130642300137100ustar00rootroot00000000000000Chris Warrick Patrick Schneeweis upass-0.3.0/CHANGELOG.rst000066400000000000000000000031541334130642300146700ustar00rootroot00000000000000===================== Appendix C. Changelog ===================== :Info: This is the changelog for upass. :Author: Chris Warrick :Copyright: © 2015-2018, Chris Warrick. :License: BSD (see /LICENSE or :doc:`Appendix B `.) :Date: 2018-08-28 :Version: 0.3.0 .. index:: CHANGELOG GitHub holds releases, too ========================== More information can be found on GitHub in the `releases section `_. Version History =============== 0.3.0 * Add password generation (by Patrick Schneeweis) 0.2.1 * Also show “no passwords” error message if only dotfiles exist (fix #19) 0.2.0 More granular copying features: users can now choose between copying the first line (old default), copying the entire text, or copying specific fields that are separated with ``: `` (colon, space). 0.1.10 * Respect ``PASSWORD_STORE_DIR`` environment variable (if it’s set) 0.1.9 * Include missing data files 0.1.8 * Universal color scheme (for dark and light terminals) * Restore Python 2 compatibility 0.1.7 * Fix mouse support (Issue #13) 0.1.6 * fix setup.py/MANIFEST.in 0.1.5 * Warn if store is empty or does not exist (Issue #5) 0.1.4 * Add j/k support for moving in the list (Issue #4) 0.1.3 * Don’t show copied passwords (Issue #3) 0.1.2 * Add mouse wheel support. 0.1.1 * Fix search form * Fix top-level passwords appearing twice * Fix d/s/c for directory listings * Allow d/s/c keys in password display mode * Copy only the first line of multiline passwords 0.1.0 Initial release. upass-0.3.0/CONTRIBUTING.rst000066400000000000000000000036551334130642300153160ustar00rootroot00000000000000============================== Appendix A. Contribution rules ============================== :Info: Those are the contribution rules for upass. :Copyright: © 2012-2018, Chris Warrick. :License: 3-clause BSD .. index:: contributing Do you want to contribute to this project? Great! I’d love to see some help, but you must comply with some rules. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. --------------- Issue reporting --------------- .. index:: issues GitHub Issues are the recommended way to report an issue. When pasting console sessions, you must paste them fully, *prompt-to-prompt*, to see all the messages and your input. Trim only stuff that you are 1000% sure that is not related to the project in question. -------------------------------------------- General preparations, rules and pull process -------------------------------------------- Prepare ======= A GitHub account is recommended. Patches by e-mail are accepted, but I’d prefer to work via GitHub. Rules ===== 1. Commits must have short, informative and logical messages. Signoffs and long messages are recommended. “Fix #xxx” is required if an issue exists. 2. The following fancy Unicode characters should be used when needed: ``— “ ” ‘ ’``. ``…`` should not appear in console output, but may appear elsewhere. 3. For Python code, use the PEP 8 coding style and PEP 257 documentation style. For other languages, K&R style applies. Braces are mandatory in all blocks (even one-line blocks). Braces are on the same lines as class names and function signatures. Use 4-space indents. Request a Pull ============== Done? Go hit the **Pull Request** button over on GitHub! Your request should be accepted shortly (assuming there are no major errors). upass-0.3.0/LICENSE000066400000000000000000000027661334130642300136640ustar00rootroot00000000000000Copyright © 2015-2018, Chris Warrick. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author of this software nor the names of contributors to this software may be used to endorse or promote products derived from this software without specific prior written consent. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. upass-0.3.0/MANIFEST.in000066400000000000000000000002311334130642300143760ustar00rootroot00000000000000graft upass graft docs graft tests include README.rst AUTHORS LICENSE CHANGELOG.rst setup.py setup.cfg requirements.txt global-exclude __pycache__ *.pyc upass-0.3.0/PKGBUILD000066400000000000000000000013261334130642300137720ustar00rootroot00000000000000# Maintainer: Chris Warrick pkgname=upass _pyname=upass pkgver=0.3.0 pkgrel=1 pkgdesc='Console UI for pass' arch=('any') url='https://github.com/Kwpolska/upass' license=('BSD') options=(!emptydirs) source=("https://files.pythonhosted.org/packages/source/${_pyname:0:1}/${_pyname}/${_pyname}-${pkgver}.tar.gz") md5sums=('8b47c99a5be8dca5e302e9f8de8b3ee7') depends=('pass' 'python' 'python-setuptools' 'python-urwid' 'python-pyperclip') prepare() { cd "${srcdir}/${_pyname}-${pkgver}" } package() { cd "${srcdir}/${_pyname}-${pkgver}" python3 setup.py install --root="${pkgdir}/" --optimize=1 install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" } # vim:set ts=2 sw=2 et: upass-0.3.0/PKGBUILD-git000066400000000000000000000014671334130642300145610ustar00rootroot00000000000000# Maintainer: Chris Warrick pkgname=upass-git _pyname=upass _gitname=upass pkgver=0.3.0 pkgrel=1 pkgdesc='Console UI for pass (git version)' arch=('any') url='https://github.com/Kwpolska/upass' license=('BSD') options=(!emptydirs) source=("git+https://github.com/Kwpolska/${_gitname}") md5sums=('SKIP') depends=('pass' 'python' 'python-setuptools' 'python-urwid' 'python-pyperclip') makedepends=('git') provides=('upass') conflicts=('upass') prepare() { cd "${srcdir}/${_gitname}" } package() { cd "${srcdir}/${_gitname}" python3 setup.py install --root="${pkgdir}/" --optimize=1 install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" } pkgver() { cd "${srcdir}/${_gitname}" git describe --long | sed -E 's/([^-]*-g)/r\1/;s/-/./g;s/^v//' } # vim:set ts=2 sw=2 et: upass-0.3.0/README000066400000000000000000000050751334130642300135330ustar00rootroot00000000000000============================ upass. Console UI for pass. ============================ :Info: This is the README file for upass. :Author: Chris Warrick :Copyright: © 2015-2018, Chris Warrick. :Date: 2018-08-28 :Version: 0.3.0 .. image:: https://chriswarrick.com/galleries/upass/directory-listing.png INSTALLATION ------------ :: pip install upass There are also AUR packages available. USAGE ----- Run ``upass`` and use the friendly console interface. CONFIGURATION ------------- upass stores its config in ``~/.config/kwpolska/upass/upass.ini`` (but it respects ``XDG_CONFIG_HOME`` if you changed it). Available options: * keys — keybinding configuration. * help, display, copy, refresh, search, quit — set key bindings for commands, space-separated (eg. ``quit=q f10`` will make ``q`` and ``f10`` keybindings for ``quit``) * ``uplevel_h`` — on/off, use the ``h`` key as a back button, make sure to change your ``help`` key bindings * ``downlevel_l`` — on/off, use the ``l`` key to open directory/password COPYRIGHT --------- Copyright © 2015-2018, Chris Warrick. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author of this software nor the names of contributors to this software may be used to endorse or promote products derived from this software without specific prior written consent. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. upass-0.3.0/README.rst000066400000000000000000000050751334130642300143420ustar00rootroot00000000000000============================ upass. Console UI for pass. ============================ :Info: This is the README file for upass. :Author: Chris Warrick :Copyright: © 2015-2018, Chris Warrick. :Date: 2018-08-28 :Version: 0.3.0 .. image:: https://chriswarrick.com/galleries/upass/directory-listing.png INSTALLATION ------------ :: pip install upass There are also AUR packages available. USAGE ----- Run ``upass`` and use the friendly console interface. CONFIGURATION ------------- upass stores its config in ``~/.config/kwpolska/upass/upass.ini`` (but it respects ``XDG_CONFIG_HOME`` if you changed it). Available options: * keys — keybinding configuration. * help, display, copy, refresh, search, quit — set key bindings for commands, space-separated (eg. ``quit=q f10`` will make ``q`` and ``f10`` keybindings for ``quit``) * ``uplevel_h`` — on/off, use the ``h`` key as a back button, make sure to change your ``help`` key bindings * ``downlevel_l`` — on/off, use the ``l`` key to open directory/password COPYRIGHT --------- Copyright © 2015-2018, Chris Warrick. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author of this software nor the names of contributors to this software may be used to endorse or promote products derived from this software without specific prior written consent. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. upass-0.3.0/docs/000077500000000000000000000000001334130642300135745ustar00rootroot00000000000000upass-0.3.0/docs/CHANGELOG.rst000066400000000000000000000031541334130642300156200ustar00rootroot00000000000000===================== Appendix C. Changelog ===================== :Info: This is the changelog for upass. :Author: Chris Warrick :Copyright: © 2015-2018, Chris Warrick. :License: BSD (see /LICENSE or :doc:`Appendix B `.) :Date: 2018-08-28 :Version: 0.3.0 .. index:: CHANGELOG GitHub holds releases, too ========================== More information can be found on GitHub in the `releases section `_. Version History =============== 0.3.0 * Add password generation (by Patrick Schneeweis) 0.2.1 * Also show “no passwords” error message if only dotfiles exist (fix #19) 0.2.0 More granular copying features: users can now choose between copying the first line (old default), copying the entire text, or copying specific fields that are separated with ``: `` (colon, space). 0.1.10 * Respect ``PASSWORD_STORE_DIR`` environment variable (if it’s set) 0.1.9 * Include missing data files 0.1.8 * Universal color scheme (for dark and light terminals) * Restore Python 2 compatibility 0.1.7 * Fix mouse support (Issue #13) 0.1.6 * fix setup.py/MANIFEST.in 0.1.5 * Warn if store is empty or does not exist (Issue #5) 0.1.4 * Add j/k support for moving in the list (Issue #4) 0.1.3 * Don’t show copied passwords (Issue #3) 0.1.2 * Add mouse wheel support. 0.1.1 * Fix search form * Fix top-level passwords appearing twice * Fix d/s/c for directory listings * Allow d/s/c keys in password display mode * Copy only the first line of multiline passwords 0.1.0 Initial release. upass-0.3.0/docs/CONTRIBUTING.rst000066400000000000000000000036551334130642300162460ustar00rootroot00000000000000============================== Appendix A. Contribution rules ============================== :Info: Those are the contribution rules for upass. :Copyright: © 2012-2018, Chris Warrick. :License: 3-clause BSD .. index:: contributing Do you want to contribute to this project? Great! I’d love to see some help, but you must comply with some rules. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. --------------- Issue reporting --------------- .. index:: issues GitHub Issues are the recommended way to report an issue. When pasting console sessions, you must paste them fully, *prompt-to-prompt*, to see all the messages and your input. Trim only stuff that you are 1000% sure that is not related to the project in question. -------------------------------------------- General preparations, rules and pull process -------------------------------------------- Prepare ======= A GitHub account is recommended. Patches by e-mail are accepted, but I’d prefer to work via GitHub. Rules ===== 1. Commits must have short, informative and logical messages. Signoffs and long messages are recommended. “Fix #xxx” is required if an issue exists. 2. The following fancy Unicode characters should be used when needed: ``— “ ” ‘ ’``. ``…`` should not appear in console output, but may appear elsewhere. 3. For Python code, use the PEP 8 coding style and PEP 257 documentation style. For other languages, K&R style applies. Braces are mandatory in all blocks (even one-line blocks). Braces are on the same lines as class names and function signatures. Use 4-space indents. Request a Pull ============== Done? Go hit the **Pull Request** button over on GitHub! Your request should be accepted shortly (assuming there are no major errors). upass-0.3.0/docs/LICENSE.rst000066400000000000000000000035031334130642300154110ustar00rootroot00000000000000============================= Appendix B. License for upass ============================= :Info: This is the license for upass. :Author: Chris Warrick :Copyright: © 2015-2018, Chris Warrick. :License: BSD (see /LICENSE or :doc:`Appendix B `.) :Date: 2018-08-28 :Version: 0.3.0 .. index:: LICENSE Copyright © 2015-2018, Chris Warrick. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author of this software nor the names of contributors to this software may be used to endorse or promote products derived from this software without specific prior written consent. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. upass-0.3.0/docs/README.rst000066400000000000000000000050751334130642300152720ustar00rootroot00000000000000============================ upass. Console UI for pass. ============================ :Info: This is the README file for upass. :Author: Chris Warrick :Copyright: © 2015-2018, Chris Warrick. :Date: 2018-08-28 :Version: 0.3.0 .. image:: https://chriswarrick.com/galleries/upass/directory-listing.png INSTALLATION ------------ :: pip install upass There are also AUR packages available. USAGE ----- Run ``upass`` and use the friendly console interface. CONFIGURATION ------------- upass stores its config in ``~/.config/kwpolska/upass/upass.ini`` (but it respects ``XDG_CONFIG_HOME`` if you changed it). Available options: * keys — keybinding configuration. * help, display, copy, refresh, search, quit — set key bindings for commands, space-separated (eg. ``quit=q f10`` will make ``q`` and ``f10`` keybindings for ``quit``) * ``uplevel_h`` — on/off, use the ``h`` key as a back button, make sure to change your ``help`` key bindings * ``downlevel_l`` — on/off, use the ``l`` key to open directory/password COPYRIGHT --------- Copyright © 2015-2018, Chris Warrick. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the author of this software nor the names of contributors to this software may be used to endorse or promote products derived from this software without specific prior written consent. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. upass-0.3.0/docs/conf.py000066400000000000000000000163561334130642300151060ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # upass documentation build configuration file, created by # sphinx-quickstart on Fri Dec 14 21:02:58 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'upass' copyright = u'2015-2018, Chris Warrick' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.3.0' # The full version, including alpha/beta/rc tags. release = '0.3.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'upassdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'upass.tex', u'upass Documentation', u'Chris Warrick', 'manual'), ] latex_elements = {'papersize': 'a4paper', 'fontpkg': '\\usepackage{tgheros}', 'fncychap': '\\usepackage[Sonny]{fncychap}'} # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'upass', u'upass Documentation', [u'Chris Warrick'], 1) ] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'http://docs.python.org/': None} upass-0.3.0/docs/html/000077500000000000000000000000001334130642300145405ustar00rootroot00000000000000upass-0.3.0/docs/html/index.html000066400000000000000000000003211334130642300165310ustar00rootroot00000000000000 The docs are at upass.rtfd.org. You will be redirected there in a while. If not, click the link above. upass-0.3.0/docs/index.rst000066400000000000000000000003301334130642300154310ustar00rootroot00000000000000======== upass ======== .. toctree:: :maxdepth: 2 README for upass CONTRIBUTING LICENSE CHANGELOG Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` upass-0.3.0/release000077500000000000000000000131751334130642300142210ustar00rootroot00000000000000#!/bin/zsh # The Release Script # Part of the Python Project Template. # Copyright © 2013-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. . .pypt/config function status { echo $@ } function warning { echo 'WARNING: '$@ } function error { echo 'ERROR: '$@ } function cleanup { rm -rf $PROJECTLC.egg-info build || true rm -rf **/__pycache__ || true } function cleanup_cmfn { [[ -e $cmfn ]] && rm $cmfn || true [[ -e $cmfn2 ]] && rm $cmfn2 || true } status '*** Chris Warrick’s Release Scripts (PyPT)' echo -n "Version number: " read version echo $version | grep '^[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}$' > /dev/null if [[ $? != 0 ]]; then echo $version | grep '^[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}\-[0-9A-Za-z-]\{1,\}$' > /dev/null if [[ $? != 0 ]]; then warning 'version number is not compliant with versioning scheme (Semantic Versioning 2.0)' echo -n 'Continue? [y/N] ' read vercont if [[ $vercont == 'y' || $vercont == 'Y' ]]; then echo 'Continuing.' else exit 2 fi else status 'NOTICE: pre-release version number in use.' echo -n 'Continue? [Y/n] ' read vercont if [[ $vercont == 'n' || $vercont == 'N' ]]; then exit 2 else echo 'Continuing.' fi fi fi # Creating all the dates at the exact same time. date=$(date '+%Y-%m-%d') datel=$(date '+%Y-%m-%d %H:%M%z') #datep=$(date '+%Y%m%d') dates=$(date '+%s') cmfn=$PWD/.git/kwrs-$dates cmfn2=$cmfn"-commit" cleanup cleanup_cmfn git add -A --ignore-errors . cat > $cmfn <> $cmfn if [[ "$EDITOR" == 'vim' || "$EDITOR" == '/usr/bin/vim' ]]; then $EDITOR -c 'set filetype=gitcommit' $cmfn elif [[ $EDITOR == '' ]]; then vim -c 'set filetype=gitcommit' $cmfn else $EDITOR $cmfn fi .pypt/commitlog $cmfn $PWD $version status 'Replacing versions and dates in files...' sed "s/version=.*/version='$version',/g" setup.py -i sed "s/version = .*/version = '$version'/g" docs/conf.py -i sed "s/release = .*/release = '$version'/g" docs/conf.py -i sed "s/:Version: .*/:Version: $version/g" docs/**/*.rst -i sed "s/# $PROJECT v.*/# $PROJECT v$version/" $PROJECTLC/**/*.py -i sed "s/__version__ = .*/__version__ = '$version'/g" $PROJECTLC/__init__.py -i sed "s/:Date: .*/:Date: $date/g" docs/*.rst -i [[ -e "PKGBUILD" ]] && sed "s/pkgver=.*/pkgver=$version/g" PKGBUILD -i || true [[ -e "PKGBUILD-git" ]] && sed "s/pkgver=.*/pkgver=$version/g" PKGBUILD-git -i || true cp docs/README.rst docs/CHANGELOG.rst docs/CONTRIBUTING.rst . cp docs/README.rst README status 'Generating locales...' ./.pypt/localegen status 'Importing...' python -c "import $PROJECTLC" if [[ $? != 0 ]]; then error "Import failed. Fix your code or don't come back." exit 1 fi if [[ -e tests ]]; then status 'Running tests...' pytest tests/ if [[ $? != 0 ]]; then error "Tests failed. Fix your code or don't come back." exit 1 fi fi status 'Running pre-sdist.hook...' . .pypt/hooks/pre-sdist.hook status 'This is the last chance to quit. Hit ^C now if you want to.' read bailout ./setup.py sdist bdist_wheel || exit $? twine upload -s dist/$PROJECTLC-$version.tar.gz dist/$PROJECTLC-$version*.whl || exit $? if [[ -e PKGBUILD ]]; then status 'Updating AUR PKGBUILDs...' md5out=$(md5sum 'dist/'$PROJECTLC'-'$version'.tar.gz'|awk '{print $1}') sed "s/md5sums=.*/md5sums=('$md5out')/" PKGBUILD -i fi cleanup git add -A --ignore-errors . || exit $? git commit -S -asF $cmfn2 || exit $? git tag -sm "Version $version" v$version || exit $? git push --follow-tags origin master || exit $? .pypt/ghrel $cmfn $PWD $GITUSER/$GITREPO v$version cleanup_cmfn status "Done!" . .pypt/hooks/post-release.hook upass-0.3.0/requirements.txt000066400000000000000000000000201334130642300161200ustar00rootroot00000000000000urwid pyperclip upass-0.3.0/setup.cfg000066400000000000000000000000261334130642300144630ustar00rootroot00000000000000[wheel] universal = 1 upass-0.3.0/setup.py000077500000000000000000000027611334130642300143670ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- import io from setuptools import setup with open('requirements.txt', 'r') as fh: dependencies = [l.strip() for l in fh] setup(name='upass', version='0.3.0', description='Console UI for pass.', keywords='upass', author='Chris Warrick', author_email='chris@chriswarrick.com', url='https://github.com/Kwpolska/upass', license='3-clause BSD', long_description=io.open('./docs/README.rst', 'r', encoding='utf-8').read(), platforms='any', zip_safe=False, include_package_data=True, # http://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=['Development Status :: 3 - Alpha', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7'], packages=['upass'], install_requires=dependencies, extras_require={ ':python_version == "2.7"': ['configparser'] }, entry_points={ 'console_scripts': [ 'upass = upass.__main__:main', ] }, ) upass-0.3.0/upass/000077500000000000000000000000001334130642300137775ustar00rootroot00000000000000upass-0.3.0/upass/__init__.py000077500000000000000000000054441334130642300161220ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # upass v0.3.0 # Console UI for pass. # Copyright © 2015-2018, Chris Warrick. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions, and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. Neither the name of the author of this software nor the names of # contributors to this software may be used to endorse or promote # products derived from this software without specific prior written # consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ Console UI for pass. :Copyright: © 2015-2018, Chris Warrick. :License: BSD (see /LICENSE). """ import os import pkg_resources import configparser __title__ = 'upass' __version__ = '0.3.0' __author__ = 'Chris Warrick' __license__ = '3-clause BSD' __docformat__ = 'restructuredtext en' __all__ = ('config',) # Config directory setup confhome = os.getenv('XDG_CONFIG_HOME') if confhome is None: confhome = os.path.expanduser('~/.config/') kwdir = os.path.join(confhome, 'kwpolska') confdir = os.path.join(kwdir, 'upass') confpath = os.path.join(confdir, 'upass.ini') if not os.path.exists(confhome): os.mkdir(confhome) if not os.path.exists(kwdir): os.mkdir(kwdir) if not os.path.exists(confdir): os.mkdir(confdir) if not os.path.exists(confpath): print("upass.ini does not exist, creating") with open(confpath, 'wb') as fh: fh.write(pkg_resources.resource_string( 'upass', 'data/upass.ini.skel')) print("created " + confpath) # Configuration file support config = configparser.ConfigParser() config.read_string(pkg_resources.resource_string( 'upass', 'data/upass.ini.skel').decode('utf-8')) config.read([confpath], encoding='utf-8') upass-0.3.0/upass/__main__.py000077500000000000000000000540301334130642300160760ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # upass v0.3.0 # Console UI for pass. # Copyright © 2015-2018, Chris Warrick. # See /LICENSE for licensing information. """ upass user interface. :Copyright: © 2015-2018, Chris Warrick. :License: BSD (see /LICENSE). """ import os import re import sys import upass import urwid import pyperclip import subprocess __all__ = ('main', 'App') HELP = """upass is an interface for pass, the standard unix password manager. Use up/down arrows or jk (vim-style) and Enter to navigate the directory tree. Available commands (with default key bindings): d display s display c copy g generate r refresh / search h help q quit upass requires pass installed and in $PATH: http://www.passwordstore.org/""" # Case folding if sys.version_info[0] == 2: try: from py2casefold import casefold except ImportError: casefold = str.lower # workaround else: casefold = str.casefold class PasswordButton(urwid.Button): """A password button.""" def __init__(self, caption, callback): """Initialize a button.""" super(PasswordButton, self).__init__("") self.caption = caption[:-len('.gpg')] urwid.connect_signal(self, 'click', callback, self.caption) self._w = urwid.AttrMap(urwid.SelectableIcon( [u'├ ', self.caption], 0), 'button', 'button_reversed') class DirectoryButton(urwid.Button): """An password button.""" def __init__(self, caption, callback): """Initialize a button.""" super(DirectoryButton, self).__init__("") self.caption = caption urwid.connect_signal(self, 'click', callback, self.caption) self._w = urwid.AttrMap(urwid.SelectableIcon( [u'├ ', self.caption, '/'], 0), 'button', 'button_reversed') class ActionButton(urwid.Button): """An action button.""" def __init__(self, caption, callback, user_arg=None): """Initialize a button.""" super(ActionButton, self).__init__("") self.caption = caption urwid.connect_signal(self, 'click', callback, user_arg) self._w = urwid.AttrMap(urwid.SelectableIcon( [u'> ', self.caption], 0), 'button', 'button_reversed') class BackButton(urwid.Button): """A back button.""" def __init__(self, caption, callback, user_arg, app): """Initialize a button.""" super(BackButton, self).__init__("") self.caption = caption urwid.connect_signal(self, 'click', callback, user_arg) self._w = urwid.AttrMap(urwid.SelectableIcon( [u'< ', self.caption], 0), 'button', 'button_reversed') app.back_callback = callback app.back_arg = user_arg # h/t Heiko Noordhof @hkoof class FancyListBox(urwid.ListBox): """A list box you can scroll in fancy ways.""" def keypress(self, size, key): """Handle keypresses.""" currentfocus = self.focus_position maxindex = len(self.body) - 1 newfocus = None if key == 'home': newfocus = 0 elif key == 'end': newfocus = maxindex elif key == 'k' and self._app.mode not in ('search', 'generate'): newfocus = currentfocus - 1 elif key == 'j' and self._app.mode not in ('search', 'generate'): newfocus = currentfocus + 1 if newfocus is not None: if newfocus < 0: newfocus = 0 elif newfocus > maxindex: newfocus = maxindex self.set_focus(newfocus) return super(FancyListBox, self).keypress(size, key) def mouse_event(self, size, event, button, col, row, focus): """Handle scroll events.""" currentfocus = self.focus_position newfocus = None maxindex = len(self.body) - 1 if button == 4: newfocus = currentfocus - 3 elif button == 5: newfocus = currentfocus + 3 if newfocus is not None: if newfocus < 0: newfocus = 0 elif newfocus > maxindex: newfocus = maxindex self.set_focus(newfocus) # handle clicks return super(FancyListBox, self).mouse_event( size, event, button, col, row, focus) class EditWithEnter(urwid.Edit): kw_enter_handler = None def __init__(self, *args, **kwargs): if 'enter_handler' in kwargs: self.enter_handler = kwargs.pop('enter_handler') super(EditWithEnter, self).__init__(*args, **kwargs) def keypress(self, size, key): if key == 'enter' and self.enter_handler: self.enter_handler(self) return super(EditWithEnter, self).keypress(size, key) class App(object): """The upass app object.""" palette = [ ('header', 'white', 'dark red'), ('footer', 'white', 'dark blue'), ('footer_reversed', 'dark blue', 'white'), ('highlight', 'light blue', ''), ('error', 'light red', ''), ('button', 'default', ''), ('button_reversed', 'standout', ''), ] back_callback = None back_arg = None def __init__(self): """Initialize the app.""" self.header = urwid.AttrWrap(urwid.Text( "upass v{0}".format(upass.__version__)), 'header') listbox_content = [urwid.Text('LOADING')] self.box = FancyListBox(urwid.SimpleFocusListWalker(listbox_content)) self.box._app = self self.home = os.environ.get('PASSWORD_STORE_DIR', os.path.expanduser('~/.password-store')) if os.path.exists(self.home) and os.listdir(self.home): self.refresh() self.current = '.' self.dir_load(None, self.current) else: self.show_empty_error() column_data = [ urwid.Button('DiSplay', self.display_selected), urwid.Button('Copy', self.copy_selected), urwid.Button('Generate', self.generate_password), urwid.Button('Refresh', self.refresh_and_reload), urwid.Button('/search', self.search), urwid.Button('Help', self.help), urwid.Button('Quit', self.quit), ] column_data = [urwid.AttrWrap(i, 'footer', 'footer_reversed') for i in column_data] self.footer = urwid.Columns(column_data) # Load keys from ini file ini_commands = { 'display': self.display_selected, 'copy': self.copy_selected, 'generate': self.generate_password, 'refresh': self.refresh_and_reload, 'search': self.search, 'help': self.help, 'quit': self.quit } self.keys = {} for command, handler in ini_commands.items(): bindkeys = upass.config.get('keys', command).strip().split() for k in bindkeys: self.keys[k] = handler if upass.config.getboolean('keys', 'uplevel_h'): self.keys['h'] = self.uplevel if upass.config.getboolean('keys', 'downlevel_l'): self.keys['l'] = self.downlevel self.frame = urwid.Frame(self.box, header=self.header, footer=self.footer) self.loop = urwid.MainLoop(self.frame, self.palette, unhandled_input=self._unhandled) def _unhandled(self, key): """Handle unhandled input.""" try: key = key.lower() # string == keyboard input if key in self.keys: self.keys[key]('unhandled') elif key == 'tab': if self.frame.focus_position == 'body': self.frame.focus_position = 'footer' elif self.frame.focus_position == 'footer': self.frame.focus_position = 'body' elif self.mode == 'search' and key == 'enter': self.search_results('unhandled') except AttributeError: # tuple == mouse event pass def refresh(self): """Refresh the passwords.""" self.directories = [] self.passwords = [] self.recurse(self.home, '') self.topdir_passwords = [i for i in os.listdir(self.home) if not i.startswith('.') and i not in self.directories] def refresh_and_reload(self, originator): """Refresh the passwords and rebuild the directory listing.""" self.refresh() self.load_dispatch(originator, self.current) def get_selected_password(self, originator): """Get the currently selected password.""" if self.mode in ('dir_load', 'search_results'): path = self.box.focus.caption elif self.mode in ('pass_load', 'call_pass'): path = self.current else: return None, None pathg = path + '.gpg' return path, pathg def display_selected(self, originator): """Display the currently selected password.""" path, pathg = self.get_selected_password(originator) if pathg in self.passwords: self.call_pass(originator, (path, False, None)) def copy_selected(self, originator): """Copy the currently selected password.""" path, pathg = self.get_selected_password(originator) if pathg in self.passwords: self.call_pass(originator, (path, True, False)) def generate_password(self, originator, args=None): self.mode = 'generate' if args: path, length, symbols, force = args else: path, length, symbols, force = '', 16, True, False if not path and self.current != '.': path = self.current + '/' self.set_header('GENERATE PASSWORD') self._clear_box() self.generate_password_path = EditWithEnter( ("highlight", "Password Name: "), path, multiline=False, enter_handler=self.call_generate) self.generate_password_length = urwid.IntEdit("Length: ", default=length) self.generate_password_symbols = urwid.CheckBox("Symbols", state=symbols) self.generate_password_force = urwid.CheckBox("Overwrite existing passwords with that name", state=force) self.box.body.append(self.generate_password_path) self.box.body.append(self.generate_password_length) self.box.body.append(self.generate_password_symbols) self.box.body.append(self.generate_password_force) self.box.body.append(ActionButton('GENERATE', self.call_generate)) self.box.body.append(BackButton('BACK', self.load_dispatch, self.current, self)) def call_generate(self, originator): path = self.generate_password_path.edit_text length = str(self.generate_password_length.value()) symbols = self.generate_password_symbols.state force = self.generate_password_force.state self._clear_box() self.box.body.append(urwid.AttrMap( urwid.Text( 'Generating "{0}": (length: {1}, symbols: {2}, overwrite: {3})'.format(path, length, symbols, force) ), 'highlight') ) self.loop.draw_screen() result_msg, error_msg = '', '' if not path or path.endswith('/'): error_msg = 'Invalid key path "{0}". Please enter a valid password name.'.format(path) elif self._store_key_exists(path) and not force: error_msg = ('Password with name "{0}" already exists. ' 'Please select the option to overwrite the existing password to generate a new password ' 'for this entry.'.format(path)) else: gargs = ['pass', 'generate'] if not symbols: gargs.append('-n') if force: gargs.append('-f') gargs.extend([path, length]) p = subprocess.Popen(gargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: stdout, stderr = p.communicate(timeout=5) if p.returncode == 0: self.refresh() if stdout: # Strip ANSI escape codes for text styling and colors from stdout. ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') result_msg = ansi_escape.sub('', stdout.decode('utf-8')) if stderr: error_msg = stderr.decode('utf-8') except subprocess.TimeoutExpired: error_msg = 'Command timed out: {0}'.format(' '.join(gargs)) self._clear_box() self.mode = 'generate_results' if error_msg: self.box.body.append(urwid.Text(('error', 'ERROR'))) self.box.body.append(urwid.Text(('error', error_msg))) focus_position = 2 if result_msg: self.box.body.append(urwid.Text(result_msg)) focus_position = 1 if self._store_key_exists(path): self.box.body.append(ActionButton('LOAD PASSWORD', self.pass_load, path)) self.box.body.append(ActionButton('GENERATE NEW PASSWORD', self.generate_password, (path, length, symbols, force))) self.box.body.append(BackButton('BACK TO DIRECTORY', self.dir_load, os.path.dirname(path) or '.', self)) self.box.set_focus(focus_position) def _store_key_exists(self, path): return os.path.exists(os.path.join(self.home, path + '.gpg')) def search(self, originator): """Display the search box.""" if self.mode == 'search': self.load_dispatch(originator, self.current) return self.mode = 'search' self.set_header('SEARCH') self._clear_box() self.search_input = urwid.Edit(("highlight", "Keyword: ")) self.box.body.append(self.search_input) self.box.body.append(ActionButton('SEARCH', self.search_results)) def search_results(self, originator): """Display the search results.""" query = self.search_input.text[len("Keyword: "):] query_cf = casefold(query) self.mode = 'search_results' self.set_header('SEARCH RESULTS FOR "{0}"'.format(query)) results = [i for i in self.passwords if query_cf in casefold(i)] self._clear_box() self.box.body.append(BackButton('BACK', self.load_dispatch, self.current, self)) self._make_password_buttons(results) def help(self, originator): """Display help.""" if self.mode == 'help': self.load_dispatch(originator, self.current) return self.mode = 'help' self.set_header('HELP') self._clear_box() self.box.body.append(urwid.Text(HELP)) self.box.body.append(BackButton('BACK', self.load_dispatch, self.current, self)) self.box.set_focus(1) self.frame.focus_position = 'body' def quit(self, originator): """Quit the program.""" raise urwid.ExitMainLoop() def recurse(self, home, subdir): """Recurse into directories.""" path = os.path.join(home, subdir) for i in os.listdir(path): name = os.path.join(subdir, i) if i.startswith('.'): continue elif os.path.isdir(os.path.join(path, i)): self.directories.append(name) self.recurse(home, name) else: self.passwords.append(name) def set_header(self, text): """Set the header (title bar) text.""" self.header.base_widget.set_text('[upass v{1}] {0}'.format( text, upass.__version__)) def load_dispatch(self, originator, name): """Intelligently load a directory or a password page.""" if name == '.' or name in self.directories: self.dir_load(originator, name) else: self.pass_load(originator, name) def dir_load(self, originator, dirname): """Load a directory.""" self.set_header(dirname) self.current = dirname self.mode = 'dir_load' if dirname == '.': new_directories = self.directories new_passwords = self.topdir_passwords else: dirnames = dirname + '/' new_directories = [i for i in self.directories if i.startswith(dirnames)] new_passwords = [i for i in self.passwords if i.startswith(dirnames)] self._clear_box() if dirname != '.': prevdir = os.path.normpath(dirname + '/..') self.box.body.append(BackButton('..', self.dir_load, prevdir, self)) else: if not new_directories and not new_passwords: self.show_empty_error() self.back_callback = None self._make_directory_buttons(new_directories) self._make_password_buttons(new_passwords) def pass_load(self, originator, path): """Load a password page.""" self.set_header(path) self.current = path self.mode = 'pass_load' self._clear_box() prevdir = os.path.dirname(path) or '.' self.box.body.append(BackButton('BACK', self.dir_load, prevdir, self)) self.box.body.append(ActionButton('DISPLAY', self.call_pass, (path, False, None))) self.box.body.append(ActionButton('COPY FIRST LINE', self.call_pass, (path, True, False))) self.box.body.append(ActionButton('COPY EVERYTHING', self.call_pass, (path, True, True))) self.box.body.append(ActionButton('GENERATE NEW PASSWORD', self.generate_password, (path, 16, True, True))) self.box.body.append(urwid.Text("More copy options are available after displaying the password.")) def call_pass(self, originator, args): """Call pass to get a password.""" self.current, copy, copy_key = args self.set_header(self.current) pargs = ['pass', self.current] copymsg = ' and copying output afterwards' if copy else '' self.mode = 'call_pass' self._clear_box() self.box.body.append(urwid.AttrMap( urwid.Text('Calling {0}{1}'.format(' '.join(pargs), copymsg)), 'highlight')) self.loop.draw_screen() p = subprocess.Popen(pargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode == 0: self._clear_box() try: text = stdout.decode('utf-8') except AttributeError: text = stdout copiable_entries = {} copiable_keys = [] for index, line in enumerate(text.split('\n')): entry = line.split(': ', 1) if len(entry) > 1: copiable_entries[entry[0]] = entry[1] copiable_keys.append(entry[0]) if copy: if copy_key is False: # False: copy first line copytarget = text.split('\n', 1)[0] copy_key = 'first line' elif copy_key is True: # True: copy everything copytarget = text copy_key = 'everything' else: # string: copy whatever is passed copytarget = copiable_entries[copy_key] pyperclip.copy(copytarget) self.box.body.append( urwid.AttrMap( urwid.Text('Copied {0} to clipboard.'.format(copy_key)), 'highlight')) else: self.box.body.append(urwid.Text(text.strip())) self.box.body.append(ActionButton('COPY FIRST LINE', self.call_pass, (self.current, True, False))) self.box.body.append(ActionButton('COPY EVERYTHING', self.call_pass, (self.current, True, True))) for k in copiable_keys: self.box.body.append(ActionButton('COPY {0}'.format(k), self.call_pass, (self.current, True, k))) else: self.box.body.append(urwid.Text(('error', 'ERROR'))) self.box.body.append( urwid.Text(('error', stderr.strip()))) self.box.body.append(BackButton( 'BACK TO DIRECTORY', self.dir_load, os.path.dirname(self.current) or '.', self)) self.box.body.append(BackButton( 'BACK TO PASSWORD', self.pass_load, self.current, self)) if p.returncode != 0: self.box.set_focus(3) else: self.box.set_focus(1) def uplevel(self, event=None): """Go up one level.""" if self.back_callback is not None: self.back_callback('uplevel', self.back_arg) def downlevel(self, event=None): """Go down one level.""" b = self.box.get_focus()[0] b._emit('click') def show_empty_error(self): """Show an error when the store is empty.""" self._clear_box() self.box.body.extend([ urwid.Text(("error", 'Your Password Store is empty.')), urwid.Text('Please use the `pass` command to create passwords. upass is a read-only browser.'), urwid.Text('Press q to exit.')]) def _make_directory_buttons(self, new_directories): """Add directory buttons to the box.""" for i in new_directories: self.box.body.append(DirectoryButton(i, self.dir_load)) def _make_password_buttons(self, new_passwords): """Add password buttons to the box.""" for i in new_passwords: self.box.body.append(PasswordButton(i, self.pass_load)) def _clear_box(self): del self.box.body[:] def run(self): """Run the loop.""" self.loop.run() def main(): """The main function of upass.""" return App().run() if __name__ == '__main__': try: sys.exit(main()) except KeyboardInterrupt: print("") upass-0.3.0/upass/data/000077500000000000000000000000001334130642300147105ustar00rootroot00000000000000upass-0.3.0/upass/data/upass.ini.skel000066400000000000000000000001521334130642300174770ustar00rootroot00000000000000[keys] help=? h display=d s copy=c generate=g refresh=r search=/ quit=q f10 uplevel_h=off downlevel_l=off