Browse Source

Merge branch 'master' of https://github.com/pwman3/pwman3

Conflicts:
	pwman/tests/test_pwman.py
oz123 10 years ago
parent
commit
2bc29e05f0
8 changed files with 118 additions and 168 deletions
  1. 0 1
      Makefile
  2. 18 2
      pwman/tests/test_crypto_engine.py
  3. 6 38
      pwman/tests/test_factory.py
  4. 2 2
      pwman/tests/test_pwman.py
  5. 18 22
      pwman/ui/baseui.py
  6. 57 91
      pwman/ui/tools.py
  7. 2 2
      pwman/util/config.py
  8. 15 10
      setup.py

+ 0 - 1
Makefile

@@ -50,7 +50,6 @@ coverage-run:
 	@coverage html
 	@coverage html
 
 
 coverage: coverage-run
 coverage: coverage-run
-	@rm test.db
 
 
 docs:
 docs:
 	#rm -f docs/manutils.rst
 	#rm -f docs/manutils.rst

+ 18 - 2
pwman/tests/test_crypto_engine.py

@@ -1,3 +1,21 @@
+# ============================================================================
+# This file is part of Pwman3.
+#
+# Pwman3 is free software; you can redistribute iut and/or modify
+# it under the terms of the GNU General Public License, version 2
+# as published by the Free Software Foundation;
+#
+# Pwman3 is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Pwman3; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+# ============================================================================
+# Copyright (C) 2012, 2013, 2014 Oz Nahum Tiram <nahumoz@gmail.com>
+# ============================================================================
 import unittest
 import unittest
 import os
 import os
 import time
 import time
@@ -17,8 +35,6 @@ default_config = {'Global': {'umask': '0100', 'colors': 'yes',
                                                        "history")}
                                                        "history")}
                   }
                   }
 
 
-#config.set_defaults(default_config)
-
 give_key = lambda msg: "12345"
 give_key = lambda msg: "12345"
 give_wrong_key = lambda msg: "verywrongtkey"
 give_wrong_key = lambda msg: "verywrongtkey"
 
 

+ 6 - 38
pwman/tests/test_factory.py

@@ -17,51 +17,19 @@
 # Copyright (C) 2013-2014 Oz Nahum Tiram <nahumoz@gmail.com>
 # Copyright (C) 2013-2014 Oz Nahum Tiram <nahumoz@gmail.com>
 # ============================================================================
 # ============================================================================
 
 
-#from pwman.data.nodes import NewNode
-#from pwman.data.tags import TagNew
-from pwman.data import factory
-from pwman.data.drivers.sqlite import DatabaseException, SQLite
-from pwman.ui import get_ui_platform
-from pwman.data.database import __DB_FORMAT__
 import sys
 import sys
 import unittest
 import unittest
 import os
 import os
 import os.path
 import os.path
-
-dummyfile = """
-[Encryption]
-
-[Readline]
-
-[Global]
-xsel = /usr/bin/xsel
-colors = yes
-umask = 0100
-cls_timeout = 5
-
-[Database]
-"""
-
-
-#def node_factory(username, password, url, notes, tags=None):
-#    node = NewNode()
-#    node.username = username
-#    node.password = password
-#    node.url = url
-#    node.notes = notes
-#    tags = [TagNew(tn) for tn in tags]
-#    node.tags = tags
-
-#    return node
-
-_saveconfig = False
-
-PwmanCliNew, OSX = get_ui_platform(sys.platform)
-
-
+from pwman.data import factory
+from pwman.data.drivers.sqlite import DatabaseException, SQLite
+from pwman.ui import get_ui_platform
+from pwman.data.database import __DB_FORMAT__
 from .test_tools import (SetupTester)
 from .test_tools import (SetupTester)
 
 
+PwmanCliNew, OSX = get_ui_platform(sys.platform)
 testdb = os.path.join(os.path.dirname(__file__), "test.pwman.db")
 testdb = os.path.join(os.path.dirname(__file__), "test.pwman.db")
+_saveconfig = False
 
 
 
 
 class TestFactory(unittest.TestCase):
 class TestFactory(unittest.TestCase):

+ 2 - 2
pwman/tests/test_pwman.py

@@ -21,7 +21,7 @@
 import os
 import os
 import sys
 import sys
 import unittest
 import unittest
-from .test_tools import (SetupTester)
+# from .test_tools import (SetupTester)
 from .test_crypto_engine import CryptoEngineTest, TestPassGenerator
 from .test_crypto_engine import CryptoEngineTest, TestPassGenerator
 from .test_config import TestConfig
 from .test_config import TestConfig
 from .test_sqlite import TestSQLite
 from .test_sqlite import TestSQLite
@@ -42,7 +42,7 @@ sys.path.insert(0, os.getcwd())
 # check if old DB exists, if so remove it.
 # check if old DB exists, if so remove it.
 # excuted only once when invoked upon import or
 # excuted only once when invoked upon import or
 # upon run
 # upon run
-SetupTester().clean()
+# SetupTester().clean()
 
 
 
 
 def suite():
 def suite():

+ 18 - 22
pwman/ui/baseui.py

@@ -19,7 +19,6 @@
 from __future__ import print_function
 from __future__ import print_function
 import sys
 import sys
 import os
 import os
-import getpass
 import ast
 import ast
 import csv
 import csv
 import time
 import time
@@ -31,7 +30,8 @@ from pwman.ui import tools
 from pwman.util.crypto_engine import CryptoEngine
 from pwman.util.crypto_engine import CryptoEngine
 from pwman.util.crypto_engine import zerome
 from pwman.util.crypto_engine import zerome
 from pwman.ui.tools import CliMenuItem
 from pwman.ui.tools import CliMenuItem
-from pwman.ui.tools import CMDLoop
+from pwman.ui.tools import CMDLoop, get_or_create_pass
+
 
 
 if sys.version_info.major > 2:  # pragma: no cover
 if sys.version_info.major > 2:  # pragma: no cover
     raw_input = input
     raw_input = input
@@ -143,7 +143,7 @@ class AliasesMixin(object):  # pragma: no cover
     def do_cp(self, args):
     def do_cp(self, args):
         self.do_copy(args)
         self.do_copy(args)
 
 
-    def do_EOF(self, args):
+    def do_EOF(self, args):  # pragma: no cover
         self.do_exit(args)
         self.do_exit(args)
 
 
     def do_ls(self, args):
     def do_ls(self, args):
@@ -371,31 +371,24 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
         ids = self._get_ids(args)
         ids = self._get_ids(args)
         for i in ids:
         for i in ids:
             i = int(i)
             i = int(i)
-            node = self._db.getnodes([i])[0]
+            node = self._db.getnodes([i])
+            if not node:
+                print("Node not found ...")
+                return
+            node = node[0]
             node = node[1:5] + [node[5:]]
             node = node[1:5] + [node[5:]]
             node = Node.from_encrypted_entries(*node)
             node = Node.from_encrypted_entries(*node)
             if not menu:
             if not menu:
                 menu = CMDLoop(self.config)
                 menu = CMDLoop(self.config)
                 print ("Editing node %d." % (i))
                 print ("Editing node %d." % (i))
 
 
-                menu.add(CliMenuItem("Username",
-                                     self._get_input,
-                                     node.username,
-                                     node.username))
-                menu.add(CliMenuItem("Password", self._get_secret,
-                                     node.password,
-                                     node.password))
-                menu.add(CliMenuItem("Url", self._get_input,
-                                     node.url,
-                                     node.url))
-                menunotes = CliMenuItem("Notes", self._get_input,
-                                        node.notes,
-                                        node.notes)
+                menu.add(CliMenuItem("Username", node.username))
+                menu.add(CliMenuItem("Password",  node.password))
+                menu.add(CliMenuItem("Url", node.url))
+                menunotes = CliMenuItem("Notes", node.notes)
                 menu.add(menunotes)
                 menu.add(menunotes)
                 tgetter = lambda: ', '.join(t for t in node.tags)
                 tgetter = lambda: ', '.join(t for t in node.tags)
-                menu.add(CliMenuItem("Tags", self._get_input,
-                                     tgetter(),
-                                     node.tags))
+                menu.add(CliMenuItem("Tags", tgetter()))
             menu.run(node)
             menu.run(node)
             self._db.editnode(i, **node.to_encdict())
             self._db.editnode(i, **node.to_encdict())
             # when done with node erase it
             # when done with node erase it
@@ -420,9 +413,8 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
         return sys.stdin.readline().strip()
         return sys.stdin.readline().strip()
 
 
     def _get_secret(self):
     def _get_secret(self):
-        # TODO: enable old functionallity, with password generator.
         if sys.stdin.isatty():  # pragma: no cover
         if sys.stdin.isatty():  # pragma: no cover
-            p = getpass.getpass()
+            p = get_or_create_pass()
         else:
         else:
             p = sys.stdin.readline().rstrip()
             p = sys.stdin.readline().rstrip()
         return p
         return p
@@ -450,6 +442,10 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
             print("print accepts only a single ID ...")
             print("print accepts only a single ID ...")
             return
             return
         nodes = self._db.getnodes([args])
         nodes = self._db.getnodes([args])
+        if not nodes:  # pragma: no cover
+            print("Node not found ...")
+            return
+
         node = self._db_entries_to_nodes(nodes)[0]
         node = self._db_entries_to_nodes(nodes)[0]
         print(node)
         print(node)
         flushtimeout = self.config.get_value('Global', 'cls_timeout')
         flushtimeout = self.config.get_value('Global', 'cls_timeout')

+ 57 - 91
pwman/ui/tools.py

@@ -28,8 +28,8 @@ import shlex
 import platform
 import platform
 import colorama
 import colorama
 import os
 import os
-#from pwman.util.config import get_pass_conf
 from pwman.util.callback import Callback
 from pwman.util.callback import Callback
+from pwman.util.crypto_engine import generate_password
 
 
 
 
 if sys.version_info.major > 2:  # pragma: no cover
 if sys.version_info.major > 2:  # pragma: no cover
@@ -128,56 +128,7 @@ def open_url(link, macosx=False):  # pragma: no cover
         print("Executing open_url failed with:\n", e)
         print("Executing open_url failed with:\n", e)
 
 
 
 
-def get_password(question, config):
-    # TODO: enable old functionallity, with password generator.
-    if sys.stdin.isatty():  # pragma: no cover
-        p = getpass.getpass()
-    else:
-        p = sys.stdin.readline().rstrip()
-    return p
-
-
-def getpassword(question, argsgiven=None,
-                width=_defaultwidth, echo=False,
-                reader=getpass.getpass, numerics=False, leetify=False,
-                symbols=False, special_signs=False,
-                length=None, config=None):  # pragma: no cover
-    if argsgiven == 1 or length:
-        while not length:
-            try:
-                default_length = config.get_value(
-                    'Generator', 'default_pw_length') or '8'
-                length = getinput(
-                    "Password length (default %s): " % default_length,
-                    default=default_length)
-                length = int(length)
-            except ValueError:
-                print("please enter a proper integer")
-
-        #password, dumpme = generator.generate_password(
-        #    length, length, True, symbols=leetify, numerics=numerics,
-        #    special_chars=special_signs)
-        #print ("New password: %s" % (password))
-        #return password
-    # no args given
-    while True:
-        a1 = reader(question.ljust(width))
-        if not a1:
-            return getpassword(
-                '', argsgiven=1, width=width, echo=echo, reader=reader,
-                numerics=numerics, leetify=leetify, symbols=symbols,
-                special_signs=special_signs, length=length, config=config)
-        a2 = reader("[Repeat] %s" % (question.ljust(width)))
-        if a1 == a2:
-            if leetify:
-                pass  # return generator.leetify(a1)
-            else:
-                return a1
-        else:
-            print ("Passwords don't match. Try again.")
-
-
-def get_terminal_size():
+def get_terminal_size():  # pragma: no cover
     """ getTerminalSize()
     """ getTerminalSize()
      - get width and height of console
      - get width and height of console
      - works on linux,os x,windows,cygwin(windows)
      - works on linux,os x,windows,cygwin(windows)
@@ -300,7 +251,55 @@ def getinput(question, default="", reader=raw_input,
         return reader()
         return reader()
 
 
 
 
-class CMDLoop(object):  # pragma: no cover
+def get_or_create_pass():  # pragma: no cover
+
+    p = getpass.getpass(prompt='Password (leave empty to create one):')
+    if not p:
+        while True:
+            try:
+                print("Password length (default: 8):", end="")
+                sys.stdout.flush()
+                l = sys.stdin.readline().strip()
+                l = int(l) if l else 8
+                break
+            except ValueError:
+                print("You did not enter an integer...")
+        p = generate_password(l)
+    return p
+
+
+def _get_secret():
+    if sys.stdin.isatty():  # pragma: no cover
+        p = get_or_create_pass()
+    else:
+        p = sys.stdin.readline().rstrip()
+
+    return p
+
+
+def set_selection(new_node, items, selection, reader):  # pragma: no cover
+    if selection == 0:
+        new_node.username = getinput("Username:")
+        items[0].getter = new_node.username
+    elif selection == 1:  # for password
+        new_node.password = _get_secret()
+        items[1].getter = new_node.password
+    elif selection == 2:
+        new_node.url = getinput("Url:")
+        items[2].getter = new_node.url
+    elif selection == 3:  # for notes
+        # new_node.notes = getinput("Notes:")
+        new_node.notes = reader("Notes:")
+        items[3].getter = new_node.notes
+    elif selection == 4:
+        taglist = getinput("Tags:")
+        tagstrings = taglist.split()
+        tags = [tn for tn in tagstrings]
+        new_node.tags = tags
+        items[4].getter = new_node.tags
+
+
+class CMDLoop(object):
 
 
     """
     """
     The menu that drives editing of a node
     The menu that drives editing of a node
@@ -311,16 +310,13 @@ class CMDLoop(object):  # pragma: no cover
         self.config = config
         self.config = config
 
 
     def add(self, item):
     def add(self, item):
-        if (isinstance(item, CliMenuItem)):
+        if isinstance(item, CliMenuItem):
             self.items.append(item)
             self.items.append(item)
-        else:
-            print (item.__class__)
 
 
     def run(self, new_node=None, reader=raw_input):
     def run(self, new_node=None, reader=raw_input):
         while True:
         while True:
             for i, x in enumerate(self.items):
             for i, x in enumerate(self.items):
-                current = x.getter
-                print ("%s - %s: %s" % (i + 1, x.name, current))
+                print ("%s - %s: %s" % (i + 1, x.name, x.getter))
 
 
             print("X - Finish editing")
             print("X - Finish editing")
             option = reader("Enter your choice:")[0]
             option = reader("Enter your choice:")[0]
@@ -328,48 +324,18 @@ class CMDLoop(object):  # pragma: no cover
                 print ("Selection, ", option)
                 print ("Selection, ", option)
                 # substract 1 because array subscripts start at 0
                 # substract 1 because array subscripts start at 0
                 selection = int(option) - 1
                 selection = int(option) - 1
-                # new value is created by calling the editor with the
-                # previous value as a parameter
-                # TODO: enable overriding password policy as if new node
-                # is created.
-                if selection == 0:
-                    new_node.username = getinput("Username:")
-                    self.items[0].getter = new_node.username
-                    self.items[0].setter = new_node.username
-                elif selection == 1:  # for password
-                    new_node.password = get_password("Password:", self.config)
-                    self.items[1].getter = new_node.password
-                    self.items[1].setter = new_node.password
-                elif selection == 2:
-                    new_node.url = getinput("Url:")
-                    self.items[2].getter = new_node.url
-                    self.items[2].setter = new_node.url
-                elif selection == 3:  # for notes
-                    # new_node.notes = getinput("Notes:")
-                    new_node.notes = reader("Notes:")
-                    self.items[3].getter = new_node.notes
-                    self.items[3].setter = new_node.notes
-                elif selection == 4:
-                    taglist = getinput("Tags:")
-                    tagstrings = taglist.split()
-                    tags = [tn for tn in tagstrings]
-                    #tags = ''
-                    new_node.tags = tags
-                    self.items[4].setter = new_node.tags
-                    self.items[4].getter = new_node.tags
-            except (ValueError, IndexError):
+                set_selection(new_node, self.items, selection, reader)
+            except (ValueError, IndexError):  # pragma: no cover
                 if (option.upper() == 'X'):
                 if (option.upper() == 'X'):
                     break
                     break
                 print("Invalid selection")
                 print("Invalid selection")
 
 
 
 
-class CliMenuItem(object):  # pragma: no cover
+class CliMenuItem(object):
 
 
-    def __init__(self, name, editor, getter, setter):
+    def __init__(self, name, getter):
         self.name = name
         self.name = name
-        self.editor = editor
         self.getter = getter
         self.getter = getter
-        self.setter = setter
 
 
 
 
 class CLICallback(Callback):  # pragma: no cover
 class CLICallback(Callback):  # pragma: no cover

+ 2 - 2
pwman/util/config.py

@@ -100,7 +100,7 @@ class Config(object):
     def set_value(self, section, name, value):
     def set_value(self, section, name, value):
         self.parser.set(section, name, value)
         self.parser.set(section, name, value)
 
 
-    def save(self, filename, parser=None):
+    def save(self, filename, parser=None):  # pragma: no cover
         with open(filename, "w") as fp:
         with open(filename, "w") as fp:
             if parser:
             if parser:
                 parser.write(fp)
                 parser.write(fp)
@@ -108,7 +108,7 @@ class Config(object):
                 self.parser.write(fp)
                 self.parser.write(fp)
 
 
 
 
-def get_pass_conf(config):
+def get_pass_conf(config):  # pragma: no cover
     numerics = config.get_value("Generator", "numerics").lower() == 'true'
     numerics = config.get_value("Generator", "numerics").lower() == 'true'
     # TODO: allow custom leetifying through the config
     # TODO: allow custom leetifying through the config
     leetify = config.get_value("Generator", "leetify").lower() == 'true'
     leetify = config.get_value("Generator", "leetify").lower() == 'true'

+ 15 - 10
setup.py

@@ -117,6 +117,7 @@ class BuildManPage(Command):
 
 
 
 
 class ManPageFormatter(argparse.HelpFormatter):
 class ManPageFormatter(argparse.HelpFormatter):
+
     """
     """
     Formatter class to create man pages.
     Formatter class to create man pages.
     This class relies only on the parser, and not distutils.
     This class relies only on the parser, and not distutils.
@@ -275,6 +276,7 @@ class ManPageFormatter(argparse.HelpFormatter):
 
 
 
 
 class ManPageCreator(object):
 class ManPageCreator(object):
+
     """
     """
     This class takes a little different approach. Instead of relying on
     This class takes a little different approach. Instead of relying on
     information from ArgumentParser, it relies on information retrieved
     information from ArgumentParser, it relies on information retrieved
@@ -351,16 +353,19 @@ setup(name=pwman.appname,
       install_requires=['pycrypto>=2.6',
       install_requires=['pycrypto>=2.6',
                         'colorama>=0.2.4'],
                         'colorama>=0.2.4'],
       keywords="password-manager crypto cli",
       keywords="password-manager crypto cli",
-      classifiers=[
-          'Environment :: Console',
-          'Intended Audience :: End Users/Desktop',
-          'Intended Audience :: Developers',
-          'Intended Audience :: System Administrators',
-          'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
-          'Operating System :: OS Independent',
-          'Programming Language :: Python',
-          'Programming Language :: Python :: 2.7'
-      ],
+      classifiers=['Environment :: Console',
+                   'Intended Audience :: End Users/Desktop',
+                   'Intended Audience :: Developers',
+                   'Intended Audience :: System Administrators',
+                   'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+                   'Operating System :: OS Independent',
+                   'Programming Language :: Python',
+                   'Programming Language :: Python :: 2.7'
+                   'Programming Language :: Python :: 3',
+                   'Programming Language :: Python :: 3.2',
+                   'Programming Language :: Python :: 3.3',
+                   'Programming Language :: Python :: 3.4',
+                   ],
       test_suite='pwman.tests.suite',
       test_suite='pwman.tests.suite',
       tests_require=test_requirements,
       tests_require=test_requirements,
       cmdclass={
       cmdclass={