Update to python 3
This commit is contained in:
parent
432c3359c1
commit
03a3edbd5b
|
@ -0,0 +1,125 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
language: python
|
|
||||||
python:
|
|
||||||
- "2.7"
|
|
||||||
- "pypy"
|
|
||||||
install: python setup.py install
|
|
||||||
script: nosetests
|
|
1
setup.py
1
setup.py
|
@ -16,3 +16,4 @@ setup(name='twik',
|
||||||
'console_scripts': ['twik = twik.run:main'],
|
'console_scripts': ['twik = twik.run:main'],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ class SimpleTest(unittest.TestCase):
|
||||||
|
|
||||||
def testPasswordAphanumericAndSpecialChars(self):
|
def testPasswordAphanumericAndSpecialChars(self):
|
||||||
for chars in range(4, 27):
|
for chars in range(4, 27):
|
||||||
password = self.t.getpassword('tag',
|
password = self.t.getpassword('tag', 'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 1)
|
||||||
'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 1)
|
|
||||||
if chars == 4:
|
if chars == 4:
|
||||||
self.assertEqual(password, 'm3/I')
|
self.assertEqual(password, 'm3/I')
|
||||||
if chars == 8:
|
if chars == 8:
|
||||||
|
@ -23,8 +22,7 @@ class SimpleTest(unittest.TestCase):
|
||||||
|
|
||||||
def testPasswordAlphanumeric(self):
|
def testPasswordAlphanumeric(self):
|
||||||
for chars in range(4, 27):
|
for chars in range(4, 27):
|
||||||
password = self.t.getpassword('tag',
|
password = self.t.getpassword('tag', 'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 2)
|
||||||
'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 2)
|
|
||||||
if chars == 4:
|
if chars == 4:
|
||||||
self.assertEqual(password, 'm31I')
|
self.assertEqual(password, 'm31I')
|
||||||
if chars == 8:
|
if chars == 8:
|
||||||
|
@ -38,8 +36,7 @@ class SimpleTest(unittest.TestCase):
|
||||||
|
|
||||||
def testPasswordNumeric(self):
|
def testPasswordNumeric(self):
|
||||||
for chars in range(4, 27):
|
for chars in range(4, 27):
|
||||||
password = self.t.getpassword('tag',
|
password = self.t.getpassword('tag', 'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 3)
|
||||||
'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 3)
|
|
||||||
if chars == 4:
|
if chars == 4:
|
||||||
self.assertEqual(password, '4315')
|
self.assertEqual(password, '4315')
|
||||||
if chars == 8:
|
if chars == 8:
|
||||||
|
@ -53,17 +50,14 @@ class SimpleTest(unittest.TestCase):
|
||||||
|
|
||||||
def testSize(self):
|
def testSize(self):
|
||||||
for chars in range(4, 27):
|
for chars in range(4, 27):
|
||||||
password = self.t.getpassword('tag',
|
password = self.t.getpassword('tag', 'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 1)
|
||||||
'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', chars, 1)
|
|
||||||
self.assertEqual(len(password), chars)
|
self.assertEqual(len(password), chars)
|
||||||
|
|
||||||
def testSizeWrong(self):
|
def testSizeWrong(self):
|
||||||
password = self.t.getpassword('tag',
|
password = self.t.getpassword('tag', 'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', 100, 1)
|
||||||
'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', 100, 1)
|
|
||||||
self.assertEqual(password, None)
|
self.assertEqual(password, None)
|
||||||
def testSize(self):
|
def testSize(self):
|
||||||
password = self.t.getpassword('tag',
|
password = self.t.getpassword('tag', 'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', 0, 1)
|
||||||
'TFCY2AJI-NBPU-V01E-F7CP-PJIZNRKPF25W', 'foobar', 0, 1)
|
|
||||||
self.assertEqual(password, None)
|
self.assertEqual(password, None)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
|
|
14
twik/run.py
14
twik/run.py
|
@ -18,8 +18,8 @@ GNU General Public License for more details.
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Twik. If not, see <http://www.gnu.org/licenses/>.
|
along with Twik. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
from util import Util
|
from .util import Util
|
||||||
from twik import Twik
|
from .twik import Twik
|
||||||
import getpass
|
import getpass
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
@ -34,7 +34,7 @@ def main():
|
||||||
parser.add_argument("tag", type=str,
|
parser.add_argument("tag", type=str,
|
||||||
help="generate password for a specified tag")
|
help="generate password for a specified tag")
|
||||||
parser.add_argument("-c", "--chars", type=int,
|
parser.add_argument("-c", "--chars", type=int,
|
||||||
choices=range(4, 27),
|
choices=list(range(4, 27)),
|
||||||
metavar="[4-26]",
|
metavar="[4-26]",
|
||||||
help="length of generated password [4-26]. Default: 12")
|
help="length of generated password [4-26]. Default: 12")
|
||||||
parser.add_argument("-p", "--profile", type=str, default=None,
|
parser.add_argument("-p", "--profile", type=str, default=None,
|
||||||
|
@ -53,16 +53,18 @@ def main():
|
||||||
try:
|
try:
|
||||||
master_key = getpass.getpass(prompt='Master Key: ')
|
master_key = getpass.getpass(prompt='Master Key: ')
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print "^C"
|
print("^C")
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
|
|
||||||
twik = Twik()
|
twik = Twik()
|
||||||
password = twik.getpassword(args.tag, util.get_privatekey(), master_key,
|
password = twik.getpassword(args.tag, util.get_privatekey(), master_key,
|
||||||
util.get_chars(), util.get_passord_type())
|
util.get_chars(), util.get_passord_type())
|
||||||
|
|
||||||
print "Your password is %s" % password
|
print(password, end='')
|
||||||
|
print('', file=sys.stderr)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
|
35
twik/twik.py
35
twik/twik.py
|
@ -24,12 +24,14 @@ You should have received a copy of the GNU General Public License
|
||||||
along with Twik. If not, see <http://www.gnu.org/licenses/>.
|
along with Twik. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from hashlib import sha1
|
|
||||||
from util import Util
|
|
||||||
import hmac
|
|
||||||
import getpass
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import base64
|
||||||
|
import getpass
|
||||||
|
import hmac
|
||||||
import sys
|
import sys
|
||||||
|
from hashlib import sha1
|
||||||
|
|
||||||
|
from .util import Util
|
||||||
|
|
||||||
|
|
||||||
class Twik(object):
|
class Twik(object):
|
||||||
|
@ -41,7 +43,7 @@ class Twik(object):
|
||||||
char = ord(mhash[tmp])
|
char = ord(mhash[tmp])
|
||||||
if char >= ord(cstart) and char < ord(cstart) + cnum:
|
if char >= ord(cstart) and char < ord(cstart) + cnum:
|
||||||
return mhash
|
return mhash
|
||||||
head = mhash[:pos] if pos > 0 else ""
|
head = mhash[:pos] if pos > 0 else ''
|
||||||
inject = ((seed + ord(mhash[pos])) % cnum) + ord(cstart)
|
inject = ((seed + ord(mhash[pos])) % cnum) + ord(cstart)
|
||||||
tail = mhash[pos+1:] if (pos + 1 < len(mhash)) else mhash
|
tail = mhash[pos+1:] if (pos + 1 < len(mhash)) else mhash
|
||||||
return head + chr(inject) + tail
|
return head + chr(inject) + tail
|
||||||
|
@ -54,7 +56,7 @@ class Twik(object):
|
||||||
if not inputchars[i].isdigit() and not inputchars[i].isalpha():
|
if not inputchars[i].isdigit() and not inputchars[i].isalpha():
|
||||||
inputchars[i] = chr(((seed + pivot) % 26 + ord('A')))
|
inputchars[i] = chr(((seed + pivot) % 26 + ord('A')))
|
||||||
pivot = i + 1
|
pivot = i + 1
|
||||||
return "".join(inputchars)
|
return ''.join(inputchars)
|
||||||
|
|
||||||
def converttodigits(self, mhash, seed, length):
|
def converttodigits(self, mhash, seed, length):
|
||||||
inputchars = list(mhash)
|
inputchars = list(mhash)
|
||||||
|
@ -64,28 +66,26 @@ class Twik(object):
|
||||||
inputchars[i] = chr(((seed + ord(inputchars[pivot])) % 10 +
|
inputchars[i] = chr(((seed + ord(inputchars[pivot])) % 10 +
|
||||||
ord('0')))
|
ord('0')))
|
||||||
pivot = i + 1
|
pivot = i + 1
|
||||||
return "".join(inputchars)
|
return ''.join(inputchars)
|
||||||
|
|
||||||
def generatehash(self, tag, key, length, password_type):
|
def generatehash(self, tag, key, length, password_type):
|
||||||
digest = hmac.new(key, tag, sha1).digest()
|
digest = hmac.new(str.encode(key), str.encode(tag), sha1).digest()
|
||||||
mhash = digest.encode('base64')[:-2]
|
mhash = base64.b64encode(digest)[:-1]
|
||||||
|
mhash = mhash.decode('utf-8')
|
||||||
|
seed = sum([ord(i) for i in mhash])
|
||||||
|
|
||||||
seed = 0
|
# NUMERIC
|
||||||
for i in range(0, len(mhash)):
|
|
||||||
seed += ord(mhash[i])
|
|
||||||
|
|
||||||
"""NUMERIC"""
|
|
||||||
if password_type == 3:
|
if password_type == 3:
|
||||||
mhash = self.converttodigits(mhash, seed, length)
|
mhash = self.converttodigits(mhash, seed, length)
|
||||||
else:
|
else:
|
||||||
mhash = self.injectcharacter(mhash, 0, 4, seed, length, '0', 10)
|
mhash = self.injectcharacter(mhash, 0, 4, seed, length, '0', 10)
|
||||||
"""ALPHANUMERIC_AND_SPECIAL_CHARS"""
|
# ALPHANUMERIC_AND_SPECIAL_CHARS
|
||||||
if password_type == 1:
|
if password_type == 1:
|
||||||
mhash = self.injectcharacter(mhash, 1, 4, seed, length, '!', 15)
|
mhash = self.injectcharacter(mhash, 1, 4, seed, length, '!', 15)
|
||||||
mhash = self.injectcharacter(mhash, 2, 4, seed, length, 'A', 26)
|
mhash = self.injectcharacter(mhash, 2, 4, seed, length, 'A', 26)
|
||||||
mhash = self.injectcharacter(mhash, 3, 4, seed, length, 'a', 26)
|
mhash = self.injectcharacter(mhash, 3, 4, seed, length, 'a', 26)
|
||||||
|
|
||||||
"""ALPHANUMERIC"""
|
# ALPHANUMERIC
|
||||||
if password_type == 2:
|
if password_type == 2:
|
||||||
mhash = self.removespecialcharacters(mhash, seed, length)
|
mhash = self.removespecialcharacters(mhash, seed, length)
|
||||||
|
|
||||||
|
@ -99,4 +99,5 @@ class Twik(object):
|
||||||
password = self.generatehash(mhash, master_key, length, password_type)
|
password = self.generatehash(mhash, master_key, length, password_type)
|
||||||
return password
|
return password
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
|
24
twik/util.py
24
twik/util.py
|
@ -24,8 +24,9 @@ You should have received a copy of the GNU General Public License
|
||||||
along with Twik. If not, see <http://www.gnu.org/licenses/>.
|
along with Twik. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import configparser
|
||||||
import os.path
|
import os.path
|
||||||
import ConfigParser
|
import sys
|
||||||
from random import SystemRandom
|
from random import SystemRandom
|
||||||
|
|
||||||
def privatekeygenerator():
|
def privatekeygenerator():
|
||||||
|
@ -55,7 +56,7 @@ class Util(object):
|
||||||
"""
|
"""
|
||||||
homedir = os.path.expanduser('~')
|
homedir = os.path.expanduser('~')
|
||||||
self.filename = os.path.join(homedir, '.twik.conf')
|
self.filename = os.path.join(homedir, '.twik.conf')
|
||||||
self.config = ConfigParser.ConfigParser()
|
self.config = configparser.ConfigParser()
|
||||||
self.config.read(self.filename)
|
self.config.read(self.filename)
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.chars = chars
|
self.chars = chars
|
||||||
|
@ -83,7 +84,7 @@ class Util(object):
|
||||||
break
|
break
|
||||||
if self.profile == None:
|
if self.profile == None:
|
||||||
self.profile = self.config.sections()[0]
|
self.profile = self.config.sections()[0]
|
||||||
print 'Using profile : %s' % self.profile
|
print(f'Using profile: {self.profile}', file=sys.stderr)
|
||||||
|
|
||||||
if self.profile and self.config.has_option(self.profile, 'private_key'):
|
if self.profile and self.config.has_option(self.profile, 'private_key'):
|
||||||
private_key = self.config.get(self.profile, 'private_key')
|
private_key = self.config.get(self.profile, 'private_key')
|
||||||
|
@ -104,29 +105,29 @@ class Util(object):
|
||||||
if self.profile == 'Personal':
|
if self.profile == 'Personal':
|
||||||
self.config.set(self.profile, 'default', 1)
|
self.config.set(self.profile, 'default', 1)
|
||||||
self.writeconfig()
|
self.writeconfig()
|
||||||
print 'New profile is generated'
|
print('New profile is generated')
|
||||||
self.config.read(self.filename)
|
self.config.read(self.filename)
|
||||||
return private_key
|
return private_key
|
||||||
|
|
||||||
def get_chars(self):
|
def get_chars(self):
|
||||||
config_key = '%s_chars' % self.tag
|
config_key = f'{self.tag}_chars'
|
||||||
|
|
||||||
if self.config.has_option(self.profile, config_key) and self.chars == None:
|
if self.config.has_option(self.profile, config_key) and self.chars == None:
|
||||||
self.chars = self.config.getint(self.profile, config_key)
|
self.chars = self.config.getint(self.profile, config_key)
|
||||||
else:
|
else:
|
||||||
if self.chars == None and self.config.has_option(self.profile, 'chars'):
|
if self.chars == None and self.config.has_option(self.profile, 'chars'):
|
||||||
self.chars = self.config.getint(self.profile, 'chars')
|
self.chars = self.config.getint(self.profile, 'chars')
|
||||||
self.config.set(self.profile, config_key, self.chars)
|
self.config.set(self.profile, config_key, str(self.chars))
|
||||||
self.writeconfig()
|
self.writeconfig()
|
||||||
|
|
||||||
if self.chars < 4 or self.chars > 26:
|
if self.chars < 4 or self.chars > 26:
|
||||||
print 'invalid password length value from configuration using default'
|
print('invalid password length value from configuration using default')
|
||||||
self.chars = 12
|
self.chars = 12
|
||||||
|
|
||||||
return self.chars
|
return self.chars
|
||||||
|
|
||||||
def get_passord_type(self):
|
def get_passord_type(self):
|
||||||
config_key = '%s_password_type' % self.tag
|
config_key = f'{self.tag}_password_type'
|
||||||
|
|
||||||
if self.config.has_option(self.profile, config_key) and self.pass_type == None:
|
if self.config.has_option(self.profile, config_key) and self.pass_type == None:
|
||||||
self.pass_type = self.config.getint(self.profile, config_key)
|
self.pass_type = self.config.getint(self.profile, config_key)
|
||||||
|
@ -134,13 +135,14 @@ class Util(object):
|
||||||
if self.pass_type == None and self.config.has_option(self.profile, 'password_type'):
|
if self.pass_type == None and self.config.has_option(self.profile, 'password_type'):
|
||||||
self.pass_type = self.config.getint(self.profile, 'password_type')
|
self.pass_type = self.config.getint(self.profile, 'password_type')
|
||||||
|
|
||||||
self.config.set(self.profile, config_key, self.pass_type)
|
self.config.set(self.profile, config_key, str(self.pass_type))
|
||||||
self.writeconfig()
|
self.writeconfig()
|
||||||
|
|
||||||
if self.pass_type < 1 or self.pass_type > 3:
|
if self.pass_type < 1 or self.pass_type > 3:
|
||||||
print 'invalid password type value from configuration using default'
|
print('invalid password type value from configuration using default')
|
||||||
self.pass_type = 1
|
self.pass_type = 1
|
||||||
|
|
||||||
return self.pass_type
|
return self.pass_type
|
||||||
|
|
||||||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue