ソースを参照

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

Conflicts:
	pwman/tests/test_pwman.py
oz123 10 年 前
コミット
2bc29e05f0
8 ファイル変更118 行追加168 行削除
  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: coverage-run
-	@rm test.db
 
 docs:
 	#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 os
 import time
@@ -17,8 +35,6 @@ default_config = {'Global': {'umask': '0100', 'colors': 'yes',
                                                        "history")}
                   }
 
-#config.set_defaults(default_config)
-
 give_key = lambda msg: "12345"
 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>
 # ============================================================================
 
-#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 unittest
 import os
 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)
 
+PwmanCliNew, OSX = get_ui_platform(sys.platform)
 testdb = os.path.join(os.path.dirname(__file__), "test.pwman.db")
+_saveconfig = False
 
 
 class TestFactory(unittest.TestCase):

+ 2 - 2
pwman/tests/test_pwman.py

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

+ 18 - 22
pwman/ui/baseui.py

@@ -19,7 +19,6 @@
 from __future__ import print_function
 import sys
 import os
-import getpass
 import ast
 import csv
 import time
@@ -31,7 +30,8 @@ from pwman.ui import tools
 from pwman.util.crypto_engine import CryptoEngine
 from pwman.util.crypto_engine import zerome
 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
     raw_input = input
@@ -143,7 +143,7 @@ class AliasesMixin(object):  # pragma: no cover
     def do_cp(self, args):
         self.do_copy(args)
 
-    def do_EOF(self, args):
+    def do_EOF(self, args):  # pragma: no cover
         self.do_exit(args)
 
     def do_ls(self, args):
@@ -371,31 +371,24 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
         ids = self._get_ids(args)
         for i in ids:
             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.from_encrypted_entries(*node)
             if not menu:
                 menu = CMDLoop(self.config)
                 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)
                 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)
             self._db.editnode(i, **node.to_encdict())
             # when done with node erase it
@@ -420,9 +413,8 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
         return sys.stdin.readline().strip()
 
     def _get_secret(self):
-        # TODO: enable old functionallity, with password generator.
         if sys.stdin.isatty():  # pragma: no cover
-            p = getpass.getpass()
+            p = get_or_create_pass()
         else:
             p = sys.stdin.readline().rstrip()
         return p
@@ -450,6 +442,10 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
             print("print accepts only a single ID ...")
             return
         nodes = self._db.getnodes([args])
+        if not nodes:  # pragma: no cover
+            print("Node not found ...")
+            return
+
         node = self._db_entries_to_nodes(nodes)[0]
         print(node)
         flushtimeout = self.config.get_value('Global', 'cls_timeout')

+ 57 - 91
pwman/ui/tools.py

@@ -28,8 +28,8 @@ import shlex
 import platform
 import colorama
 import os
-#from pwman.util.config import get_pass_conf
 from pwman.util.callback import Callback
+from pwman.util.crypto_engine import generate_password
 
 
 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)
 
 
-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()
      - get width and height of console
      - works on linux,os x,windows,cygwin(windows)
@@ -300,7 +251,55 @@ def getinput(question, default="", reader=raw_input,
         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
@@ -311,16 +310,13 @@ class CMDLoop(object):  # pragma: no cover
         self.config = config
 
     def add(self, item):
-        if (isinstance(item, CliMenuItem)):
+        if isinstance(item, CliMenuItem):
             self.items.append(item)
-        else:
-            print (item.__class__)
 
     def run(self, new_node=None, reader=raw_input):
         while True:
             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")
             option = reader("Enter your choice:")[0]
@@ -328,48 +324,18 @@ class CMDLoop(object):  # pragma: no cover
                 print ("Selection, ", option)
                 # substract 1 because array subscripts start at 0
                 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'):
                     break
                 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.editor = editor
         self.getter = getter
-        self.setter = setter
 
 
 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):
         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:
             if parser:
                 parser.write(fp)
@@ -108,7 +108,7 @@ class Config(object):
                 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'
     # TODO: allow custom leetifying through the config
     leetify = config.get_value("Generator", "leetify").lower() == 'true'

+ 15 - 10
setup.py

@@ -117,6 +117,7 @@ class BuildManPage(Command):
 
 
 class ManPageFormatter(argparse.HelpFormatter):
+
     """
     Formatter class to create man pages.
     This class relies only on the parser, and not distutils.
@@ -275,6 +276,7 @@ class ManPageFormatter(argparse.HelpFormatter):
 
 
 class ManPageCreator(object):
+
     """
     This class takes a little different approach. Instead of relying on
     information from ArgumentParser, it relies on information retrieved
@@ -351,16 +353,19 @@ setup(name=pwman.appname,
       install_requires=['pycrypto>=2.6',
                         'colorama>=0.2.4'],
       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',
       tests_require=test_requirements,
       cmdclass={