|
@@ -64,38 +64,38 @@ class HelpUIMixin(object): # pragma: no cover
|
|
|
"""
|
|
|
|
|
|
def _usage(self, string):
|
|
|
- print ("Usage: %s" % (string))
|
|
|
+ print("Usage: %s" % (string))
|
|
|
|
|
|
def help_open(self):
|
|
|
self._usage("open|o <ID>")
|
|
|
- print ("Launch default browser with 'xdg-open url',\n",
|
|
|
- "the url must contain http:// or https://.")
|
|
|
+ print("Launch default browser with 'xdg-open url',\n",
|
|
|
+ "the url must contain http:// or https://.")
|
|
|
|
|
|
def help_copy(self):
|
|
|
self._usage("copy|cp <ID>")
|
|
|
- print ("Copy password to X clipboard (xsel required)")
|
|
|
+ print("Copy password to X clipboard (xsel required)")
|
|
|
|
|
|
def help_cls(self):
|
|
|
self._usage("cls")
|
|
|
- print ("Clear the Screen from information.")
|
|
|
+ print("Clear the Screen from information.")
|
|
|
|
|
|
def help_list(self):
|
|
|
self._usage("list|ls <tag> ...")
|
|
|
- print ("List nodes that match current or specified filter.",
|
|
|
- " ls is an alias.")
|
|
|
+ print("List nodes that match current or specified filter.",
|
|
|
+ " ls is an alias.")
|
|
|
|
|
|
def help_delete(self):
|
|
|
self._usage("delete|rm <ID|tag> ...")
|
|
|
- print ("Deletes nodes.")
|
|
|
+ print("Deletes nodes.")
|
|
|
self._mult_id_help()
|
|
|
|
|
|
def help_help(self):
|
|
|
self._usage("help|h [topic]")
|
|
|
- print ("Prints a help message for a command.")
|
|
|
+ print("Prints a help message for a command.")
|
|
|
|
|
|
def help_edit(self):
|
|
|
self._usage("edit <ID|tag> ... ")
|
|
|
- print ("Edits a nodes.")
|
|
|
+ print("Edits a nodes.")
|
|
|
|
|
|
def help_export(self):
|
|
|
self._usage("export [{'filename': 'foo.csv', 'delimiter':'|'}] ")
|
|
@@ -103,13 +103,13 @@ class HelpUIMixin(object): # pragma: no cover
|
|
|
|
|
|
def help_new(self):
|
|
|
self._usage("new")
|
|
|
- print ("Creates a new node.,",
|
|
|
- "You can override default config settings the following way:\n",
|
|
|
- "pwman> n {'leetify':False, 'numerics':True}")
|
|
|
+ print("Creates a new node.,",
|
|
|
+ "You can override default config settings the following way:\n",
|
|
|
+ "pwman> n {'leetify':False, 'numerics':True}")
|
|
|
|
|
|
def help_print(self):
|
|
|
self._usage("print <ID|tag> ...")
|
|
|
- print ("Displays a node. ")
|
|
|
+ print("Displays a node. ")
|
|
|
self._mult_id_help()
|
|
|
|
|
|
def _mult_id_help(self):
|
|
@@ -175,15 +175,11 @@ class AliasesMixin(object): # pragma: no cover
|
|
|
self.do_new(arg)
|
|
|
|
|
|
|
|
|
-class BaseCommands(HelpUIMixin, AliasesMixin):
|
|
|
+class BaseUtilsMixin:
|
|
|
|
|
|
- @property
|
|
|
- def _xsel(self): # pragma: no cover
|
|
|
- if self.hasxsel:
|
|
|
- return True
|
|
|
-
|
|
|
- def do_EOF(self, args):
|
|
|
- return self.do_exit(args)
|
|
|
+ """Helper class for storing all privates, useful for testing these methods
|
|
|
+ directly
|
|
|
+ """
|
|
|
|
|
|
def _get_ids(self, args):
|
|
|
"""
|
|
@@ -209,6 +205,113 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
|
|
|
print("Could not understand your input...")
|
|
|
return ids
|
|
|
|
|
|
+ def _get_tags(self, default=None, reader=raw_input):
|
|
|
+ """
|
|
|
+ Read tags from user input.
|
|
|
+ Tags are simply returned as a list
|
|
|
+ """
|
|
|
+ # TODO: add method to read tags from db, so they
|
|
|
+ # could be used for tab completer
|
|
|
+ print("Tags: ", end="")
|
|
|
+ sys.stdout.flush()
|
|
|
+ taglist = sys.stdin.readline()
|
|
|
+ tagstrings = taglist.split()
|
|
|
+ tags = [tn for tn in tagstrings]
|
|
|
+ return tags
|
|
|
+
|
|
|
+ def _prep_term(self):
|
|
|
+ self.do_cls('')
|
|
|
+ if sys.platform != 'win32':
|
|
|
+ rows, cols = tools.gettermsize()
|
|
|
+ else: # pragma: no cover
|
|
|
+ rows, cols = 18, 80 # fix this !
|
|
|
+
|
|
|
+ return rows, cols
|
|
|
+
|
|
|
+ def _format_line(self, tag_pad, nid="ID", user="USER", url="URL",
|
|
|
+ tags="TAGS"):
|
|
|
+ return ("{ID:<3} {USER:<{us}}{URL:<{ur}}{Tags:<{tg}}"
|
|
|
+ "".format(ID=nid, USER=user,
|
|
|
+ URL=url, Tags=tags, us=25,
|
|
|
+ ur=25, tg=20))
|
|
|
+
|
|
|
+ def _print_node_line(self, node, rows, cols):
|
|
|
+ tagstring = ','.join([t.decode() for t in node.tags])
|
|
|
+ fmt = self._format_line(cols, node._id, node.username,
|
|
|
+ node.url[:20] + '...' if (len(node.url) > 22)
|
|
|
+ else node.url,
|
|
|
+ tagstring)
|
|
|
+ formatted_entry = tools.typeset(fmt, Fore.YELLOW, False)
|
|
|
+ print(formatted_entry)
|
|
|
+
|
|
|
+ def _get_node_ids(self, args):
|
|
|
+ filter = None
|
|
|
+ if args:
|
|
|
+ filter = args.split()[0]
|
|
|
+ ce = CryptoEngine.get()
|
|
|
+ filter = ce.encrypt(filter)
|
|
|
+ nodeids = self._db.listnodes(filter=filter)
|
|
|
+ return nodeids
|
|
|
+
|
|
|
+ def _db_entries_to_nodes(self, raw_nodes):
|
|
|
+ _nodes_inst = []
|
|
|
+ # user, pass, url, notes
|
|
|
+ for node in raw_nodes:
|
|
|
+ _nodes_inst.append(Node.from_encrypted_entries(
|
|
|
+ node[1],
|
|
|
+ node[2],
|
|
|
+ node[3],
|
|
|
+ node[4],
|
|
|
+ node[5:]))
|
|
|
+ _nodes_inst[-1]._id = node[0]
|
|
|
+ return _nodes_inst
|
|
|
+
|
|
|
+ def _get_input(self, prompt):
|
|
|
+ print(prompt, end="")
|
|
|
+ sys.stdout.flush()
|
|
|
+ return sys.stdin.readline().strip()
|
|
|
+
|
|
|
+ def _get_secret(self):
|
|
|
+ if sys.stdin.isatty(): # pragma: no cover
|
|
|
+ p = get_or_create_pass()
|
|
|
+ else:
|
|
|
+ p = sys.stdin.readline().rstrip()
|
|
|
+ return p
|
|
|
+
|
|
|
+ def _do_new(self, args):
|
|
|
+ node = {}
|
|
|
+ node['username'] = self._get_input("Username: ")
|
|
|
+ node['password'] = self._get_secret()
|
|
|
+ node['url'] = self._get_input("Url: ")
|
|
|
+ node['notes'] = self._get_input("Notes: ")
|
|
|
+ node['tags'] = self._get_tags()
|
|
|
+ node = Node(clear_text=True, **node)
|
|
|
+ self._db.add_node(node)
|
|
|
+ return node
|
|
|
+
|
|
|
+ def _do_rm(self, args):
|
|
|
+ for i in args.split():
|
|
|
+ if not i.isdigit():
|
|
|
+ print("%s is not a node ID" % i)
|
|
|
+ return None
|
|
|
+
|
|
|
+ for i in args.split():
|
|
|
+ ans = tools.getinput(("Are you sure you want to delete node {}"
|
|
|
+ " [y/N]?".format(i)))
|
|
|
+ if ans.lower() == 'y':
|
|
|
+ self._db.removenodes([i])
|
|
|
+
|
|
|
+
|
|
|
+class BaseCommands(HelpUIMixin, AliasesMixin, BaseUtilsMixin):
|
|
|
+
|
|
|
+ @property
|
|
|
+ def _xsel(self): # pragma: no cover
|
|
|
+ if self.hasxsel:
|
|
|
+ return True
|
|
|
+
|
|
|
+ def do_EOF(self, args):
|
|
|
+ return self.do_exit(args)
|
|
|
+
|
|
|
def error(self, exception): # pragma: no cover
|
|
|
if (isinstance(exception, KeyboardInterrupt)):
|
|
|
print('')
|
|
@@ -317,67 +420,6 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
|
|
|
for t in tags:
|
|
|
print(ce.decrypt(t).decode())
|
|
|
|
|
|
- def _get_tags(self, default=None, reader=raw_input):
|
|
|
- """
|
|
|
- Read tags from user input.
|
|
|
- Tags are simply returned as a list
|
|
|
- """
|
|
|
- # TODO: add method to read tags from db, so they
|
|
|
- # could be used for tab completer
|
|
|
- print("Tags: ", end="")
|
|
|
- sys.stdout.flush()
|
|
|
- taglist = sys.stdin.readline()
|
|
|
- tagstrings = taglist.split()
|
|
|
- tags = [tn for tn in tagstrings]
|
|
|
- return tags
|
|
|
-
|
|
|
- def _prep_term(self):
|
|
|
- self.do_cls('')
|
|
|
- if sys.platform != 'win32':
|
|
|
- rows, cols = tools.gettermsize()
|
|
|
- else: # pragma: no cover
|
|
|
- rows, cols = 18, 80 # fix this !
|
|
|
-
|
|
|
- return rows, cols
|
|
|
-
|
|
|
- def _format_line(self, tag_pad, nid="ID", user="USER", url="URL",
|
|
|
- tags="TAGS"):
|
|
|
- return ("{ID:<3} {USER:<{us}}{URL:<{ur}}{Tags:<{tg}}"
|
|
|
- "".format(ID=nid, USER=user,
|
|
|
- URL=url, Tags=tags, us=25,
|
|
|
- ur=25, tg=20))
|
|
|
-
|
|
|
- def _print_node_line(self, node, rows, cols):
|
|
|
- tagstring = ','.join([t for t in node.tags])
|
|
|
- fmt = self._format_line(cols, node._id, node.username,
|
|
|
- node.url[:20] + '...' if (len(node.url) > 22)
|
|
|
- else node.url,
|
|
|
- tagstring)
|
|
|
- formatted_entry = tools.typeset(fmt, Fore.YELLOW, False)
|
|
|
- print(formatted_entry)
|
|
|
-
|
|
|
- def _get_node_ids(self, args):
|
|
|
- filter = None
|
|
|
- if args:
|
|
|
- filter = args.split()[0]
|
|
|
- ce = CryptoEngine.get()
|
|
|
- filter = ce.encrypt(filter)
|
|
|
- nodeids = self._db.listnodes(filter=filter)
|
|
|
- return nodeids
|
|
|
-
|
|
|
- def _db_entries_to_nodes(self, raw_nodes):
|
|
|
- _nodes_inst = []
|
|
|
- # user, pass, url, notes
|
|
|
- for node in raw_nodes:
|
|
|
- _nodes_inst.append(Node.from_encrypted_entries(
|
|
|
- node[1],
|
|
|
- node[2],
|
|
|
- node[3],
|
|
|
- node[4],
|
|
|
- node[5:]))
|
|
|
- _nodes_inst[-1]._id = node[0]
|
|
|
- return _nodes_inst
|
|
|
-
|
|
|
def do_edit(self, args, menu=None):
|
|
|
ids = self._get_ids(args)
|
|
|
for i in ids:
|
|
@@ -391,7 +433,7 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
|
|
|
node = Node.from_encrypted_entries(*node)
|
|
|
if not menu:
|
|
|
menu = CMDLoop(self.config)
|
|
|
- print ("Editing node %d." % (i))
|
|
|
+ print("Editing node %d." % (i))
|
|
|
menu.add(CliMenuItem("Username", node.username))
|
|
|
menu.add(CliMenuItem("Password", node.password))
|
|
|
menu.add(CliMenuItem("Url", node.url))
|
|
@@ -416,29 +458,6 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
|
|
|
for idx, node in enumerate(_nodes_inst):
|
|
|
self._print_node_line(node, rows, cols)
|
|
|
|
|
|
- def _get_input(self, prompt):
|
|
|
- print(prompt, end="")
|
|
|
- sys.stdout.flush()
|
|
|
- return sys.stdin.readline().strip()
|
|
|
-
|
|
|
- def _get_secret(self):
|
|
|
- if sys.stdin.isatty(): # pragma: no cover
|
|
|
- p = get_or_create_pass()
|
|
|
- else:
|
|
|
- p = sys.stdin.readline().rstrip()
|
|
|
- return p
|
|
|
-
|
|
|
- def _do_new(self, args):
|
|
|
- node = {}
|
|
|
- node['username'] = self._get_input("Username: ")
|
|
|
- node['password'] = self._get_secret()
|
|
|
- node['url'] = self._get_input("Url: ")
|
|
|
- node['notes'] = self._get_input("Notes: ")
|
|
|
- node['tags'] = self._get_tags()
|
|
|
- node = Node(clear_text=True, **node)
|
|
|
- self._db.add_node(node)
|
|
|
- return node
|
|
|
-
|
|
|
def do_new(self, args): # pragma: no cover
|
|
|
# The cmd module stops if and of do_* return something
|
|
|
# else than None ...
|
|
@@ -465,18 +484,6 @@ class BaseCommands(HelpUIMixin, AliasesMixin):
|
|
|
_wait_until_enter(_heard_enter, float(flushtimeout))
|
|
|
self.do_cls('')
|
|
|
|
|
|
- def _do_rm(self, args):
|
|
|
- for i in args.split():
|
|
|
- if not i.isdigit():
|
|
|
- print("%s is not a node ID" % i)
|
|
|
- return None
|
|
|
-
|
|
|
- for i in args.split():
|
|
|
- ans = tools.getinput(("Are you sure you want to delete node {}"
|
|
|
- " [y/N]?".format(i)))
|
|
|
- if ans.lower() == 'y':
|
|
|
- self._db.removenodes([i])
|
|
|
-
|
|
|
def do_delete(self, args): # pragma: no cover
|
|
|
CryptoEngine.get()
|
|
|
self._do_rm(args)
|