Subversion Repositories pub

Compare Revisions

Ignore whitespace Rev 210 → Rev 211

/relevation/branches/1.2/CHANGELOG
1,9 → 1,13
$Date$
 
1.2 (2012-12):
1.2 (2013-10):
- Bugfix: Make case-insensitive search work on uppercase search
strings
- Print "notes"
- Print "notes" field
- Allow searches with "AND" operator:
- OR is used by default, as in previous versions
- New command-line flags: --and / -A and --or / -O
- New config file option: mode (possibles values 'and' and 'or')
 
1.1 (2011-07-13):
- Support cryptopy if PyCrypto is not available. Enhances
/relevation/branches/1.2/relevation.1
42,8 → 42,12
If the search string contains special/non-English characters this is likely to fail.
.IP "\fB-c\fP, \fB\-\-case-sensitive\fP " 10
When searching for text, obey case.
.IP "\fB-A\fP, \fB\-\-and\fP " 10
When multiple search terms are used, use an AND operator to combine them. All search terms will be combined in a single search, only entries that match every search term will be selected.
.IP "\fB-O\fP, \fB\-\-or\fP " 10
When multiple search terms are used, use an OR operator to combine them. A different search will be issued for each search term. This is the default and the original mode of operation.
.IP "\fB-s \fIsearch string\fR\fP, \fB\-\-search=\fIsearch string\fR\fP, \fB\fIsearch string\fR\fP " 10
Search the file for a pice of text. All fields will be searched.
Search the file for a pice of text. All fields will be searched. There's no need to use the \fB-s\fP or \fB\-\-search\fP option names, any unnamed argument will be considered a search term.
.IP "\fB-h\fP, \fB\-\-help\fP " 10
Show summary of options.
.IP "\fB\-\-version\fP " 10
58,12 → 62,15
\ [relevation]
\ file=~/passwords.revelation
\ password=my secret password
\ mode=and
.fi
.PP
.PP
Both file and password are optional, so you can store the filename without storing the password.
Both \fBfile\fP and \fBpassword\fP are optional, so you can store the filename without storing the password.
.PP
Please understand your password is stored in this file in clear text, modify the file permissions appropriately so that only your user can read it, otherwise your master password might be compromised and hence all your stored password will be too.
.PP
\fBmode\fP is optional ("\fIor\fR" by default), only the values \fIand\fR and \fIor\fR are recognized, corresponding to the matching \fB\-\-and\fP and \fB\-\-or\fP options (any other value will be ignored).
.SH "SEE ALSO"
.PP
revelation (1)
72,4 → 79,4
This manual page was written by Toni Corvera <outlyer@gmail.com>.
Permission is granted to copy, distribute and/or modify this document under the terms of a BSD 2-clause license.
.\" created by instant / docbook-to-man, Tue 05 Jul 2011, 02:25
.\" created by instant / docbook-to-man, Mon 21 Oct 2013, 06:49
/relevation/branches/1.2/manpage_source.sgml
15,7 → 15,7
<!ENTITY dhfirstname "<firstname>Toni</firstname>">
<!ENTITY dhsurname "<surname>Corvera</surname>">
<!-- Please adjust the date whenever revising the manpage. -->
<!ENTITY dhdate "<date>June 28, 2011</date>">
<!ENTITY dhdate "<date>October 21, 2013</date>">
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
<!ENTITY dhemail "<email>outlyer@gmail.com</email>">
<!ENTITY dhusername "Toni Corvera">
34,7 → 34,7
&dhsurname;
</author>
<copyright>
<year>2011</year>
<year>2011-2013</year>
<holder>&dhusername;</holder>
</copyright>
&dhdate;
121,12 → 121,26
<listitem>
<para>When searching for text, obey case.</para>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<term><option>-A</option>, <option>--and</option>
</term>
<listitem>
<para>When multiple search terms are used, use an AND operator to combine them. All search terms will be combined in a single search, only entries that match every search term will be selected.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-O</option>, <option>--or</option>
</term>
<listitem>
<para>When multiple search terms are used, use an OR operator to combine them. A different search will be issued for each search term. This is the default and the original mode of operation.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-s <replaceable>search string</replaceable></option>, <option>--search=<replaceable>search string</replaceable></option>, <option><replaceable>search string</replaceable></option>
</term>
<listitem>
<para>Search the file for a pice of text. All fields will be searched.</para>
<para>Search the file for a pice of text. All fields will be searched. There's no need to use the <option>-s</option> or <option>--search</option> option names, any unnamed argument will be considered a search term.</para>
</listitem>
</varlistentry>
 
153,9 → 167,11
<para>Example `~/.relevation.conf':</para>
<programlisting>&nbsp;[relevation]
&nbsp;file=~/passwords.revelation
&nbsp;password=my secret password</programlisting>
<para>Both file and password are optional, so you can store the filename without storing the password.</para>
&nbsp;password=my secret password
&nbsp;mode=and</programlisting>
<para>Both <option>file</option> and <option>password</option> are optional, so you can store the filename without storing the password.</para>
<para>Please understand your password is stored in this file in clear text, modify the file permissions appropriately so that only your user can read it, otherwise your master password might be compromised and hence all your stored password will be too.</para>
<para><option>mode</option> is optional ("<replaceable>or</replaceable>" by default), only the values <replaceable>and</replaceable> and <replaceable>or</replaceable> are recognized, corresponding to the matching <option>--and</option> and <option>--or</option> options (any other value will be ignored).</para>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
/relevation/branches/1.2/relevation.py
99,6 → 99,8
'generic-pin': 'PIN',
'generic-port': 'Port'
}
MODE_AND='and'
MODE_OR='or'
 
def printe(s):
' Print to stderr '
114,6 → 116,8
channel.write(s)
p('%s {-f passwordfile} {-p password | -0} [search] [search2] [...]\n' % sys.argv[0])
p('\nOptions:\n')
# Reference: 80 characters
# -------------------------------------------------------------------------------
p(' -f FILE, --file=FILE Revelation password file.\n')
p(' -p PASS, --password=PASS Master password.\n')
p(' -s SEARCH, --search=SEARCH Search for string.\n')
125,6 → 129,10
p(' -t TYPE, --type=TYPE Print only entries of type TYPE.\n')
p(' With no search string, prints all entries of\n')
p(' type TYPE.\n')
p(' -A, --and When multiple search terms are used, use an AND\n')
p(' operator to combine them.\n')
p(' -O, --or When multiple search terms are used, use an OR\n')
p(' operator to combine them.\n')
p(' -x, --xml Dump unencrypted XML document.\n')
p(' -0, --stdin Read password from standard input.\n')
p(' -h, --help Print help (this message).\n')
134,6 → 142,11
def make_xpath_query(search_text=None, type_filter=None, ignore_case=True, negate_filter=False):
''' Construct the actual XPath expression
make_xpath_query(str, str, bool, bool) -> str
or
make_xpath_query(list, str, bool, bool) -> str
 
Passing a list as the second argument implies combining its elements
in the search (AND)
'''
xpath = '/revelationdata//entry'
if type_filter:
142,13 → 155,24
sign = '!='
xpath = '%s[@type%s"%s"]' % ( xpath, sign, type_filter )
if search_text:
xpath = xpath + '//text()'
if ignore_case:
# must pass lowercase to actually be case insensitive
search_text = string.lower(search_text)
xpath = '%s[contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"), "%s")]/../..' % ( xpath, search_text )
#xpath = xpath + '//text()'
needles = []
if type(search_text) == str:
needles = [ search_text, ]
else:
xpath = '%s[contains(., "%s")]/../..' % ( xpath, search_text )
needles = search_text
selector = ''
for search in needles:
if ignore_case:
# must pass lowercase to actually be case insensitive
search = string.lower(search)
# XPath 2.0 has lower-case, upper-case, matches(..., -i) etc.
selector += '//text()[contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"), "%s")]/../..' % search
else:
selector += '//text()[contains(., "%s")]/../..' % search
xpath = '%s%s' % ( xpath, selector )
if not RELEASE:
printe("> Xpath: %s\n" % xpath)
return xpath
 
def dump_all_entries(xmldata):
158,7 → 182,11
return dump_result(res, 'all')
 
def dump_entries(xmldata, search_text=None, type_filter=None, ignore_case=True, negate_filter=False):
' Dump entries from xmldata that match criteria '
''' Dump entries from xmldata that match criteria
dump_entries(str, str, str, bool, bool) -> int
or
dump_entries(str, list, str, bool, bool) -> int
'''
tree = etree.fromstring(xmldata)
xpath = make_xpath_query(search_text, type_filter, ignore_case, negate_filter)
try:
181,10 → 209,19
nr = dump_result(res, query_desc)
return nr
 
def print_wrapper(s):
def dump_single_result(typeName, name, descr, notes, fields):
printe('-------------------------------------------------------------------------------')
s = '\n'
s += 'Type: %s\n' % typeName
s += 'Name: %s\n' % name
s += 'Description: %s\n' % descr
s += 'Notes: %s\n' % notes
for field in fields:
s += '%s %s\n' % field # field, value
#s += '\n'
print s
 
def dump_result(res, query_desc, printfn=print_wrapper):
def dump_result(res, query_desc, dumpfn=dump_single_result):
''' Print query results.
dump_result(list of entries, query description) -> int
'''
194,9 → 231,11
return False
print '%d matches' % len(res)
for x in res:
printe('-------------------------------------------------------------------------------')
s = '\n'
s += 'Type: %s\n' % x.get('type')
typeName = x.get('type')
name = None
descr = None
fields = []
notes = None
for chld in x.getchildren():
n = chld.tag
val = chld.text
203,9 → 242,9
if val is None:
val = ''
if n == 'name':
s += 'Name: %s\n' % val
name = val
elif n == 'description':
s += 'Description: %s\n' % val
descr = val
elif n == 'field':
idv = chld.get('id')
if idv in TAGNAMES:
213,11 → 252,11
val = chld.text
if val is None:
val = ''
s += '%s %s\n' % ( idv, val )
# Maintain order => list
fields += [ ( idv, val ), ]
elif n == 'notes':
s += 'Notes: %s\n' % val
#s += '\n'
printfn(s)
notes = val
dumpfn(typeName, name, descr, notes, fields)
# / for chld in x.children
nr = len(res)
plural = ''
242,6 → 281,7
cfg = os.path.join(os.path.expanduser('~'), '.relevation.conf')
pw = None
fl = None
mode = MODE_OR
if os.path.isfile(cfg):
if os.access(cfg, os.R_OK):
wr = world_readable(cfg)
256,9 → 296,14
if wr: # TODO: how to check in windows?
printe('Your password can be read by anyone!!!')
pw = parser.get('relevation', 'password')
if 'mode' in ops:
mode = parser.get('relevation', 'mode')
if mode not in [ MODE_AND, MODE_OR ]:
printe('Warning: Unknown mode \'%s\' set in configuration' % mode)
mode=MODE_OR
else: # exists but not readable
printe('Configuration file (~/.relevation.conf) is not readable!')
return ( fl, pw )
return ( fl, pw, mode )
 
def decrypt_gz(key, cipher_text):
''' Decrypt cipher_text using key.
292,17 → 337,19
# individual search: ( 'value to search', 'type of search', 'type of entry to filter' )
searchTypes = []
dump_xml = False
mode = None
 
printe('Relevation v%s, (c) 2011-2012 Toni Corvera\n' % __version__)
printe('Relevation v%s, (c) 2011-2013 Toni Corvera\n' % __version__)
 
# ---------- OPTIONS ---------- #
( datafile, password ) = load_config()
( datafile, password, mode ) = load_config()
try:
# gnu_getopt requires py >= 2.3
ops, args = getopt.gnu_getopt(argv, 'f:p:s:0ciaht:x',
ops, args = getopt.gnu_getopt(argv, 'f:p:s:0ciaht:xAO',
[ 'file=', 'password=', 'search=', 'stdin',
'case-sensitive', 'case-insensitive', 'ask',
'help', 'version', 'type=', 'xml' ])
'help', 'version', 'type=', 'xml',
'and', 'or' ])
except getopt.GetoptError, err:
print str(err)
usage(sys.stderr)
355,6 → 402,10
searchTypes.append( ( iarg, neg ) )
elif opt in ( '-x', '--xml' ):
dump_xml = True
elif opt in ( '-A', '--and' ):
mode = MODE_AND
elif opt in ( '-O', '--or' ):
mode = MODE_OR
else:
printe('Unhandled option: %s' % opt)
assert False, "internal error parsing options"
396,13 → 447,23
if not ( needles or searchTypes ): # No search nor filters, print all
numhits = dump_all_entries(xmldata)
elif not searchTypes: # Simple case, all searches are text searches
for text in needles:
numhits += dump_entries(xmldata, text, 'folder', caseInsensitive, True)
if mode == MODE_OR:
for text in needles:
numhits += dump_entries(xmldata, text, 'folder', caseInsensitive, True)
else:
assert mode == MODE_AND, "Unknown boolean operation mode"
numhits += dump_entries(xmldata, needles, 'folder', caseInsensitive, True)
elif needles: # Do a search filtered for each type
for text in needles:
if mode == MODE_OR:
for text in needles:
for ( sfilter, negate ) in searchTypes:
numhits += dump_entries(xmldata, text, sfilter, caseInsensitive,
negate_filter=negate)
else:
assert mode == MODE_AND, "Unknown boolean operation mode"
for ( sfilter, negate ) in searchTypes:
numhits += dump_entries(xmldata, text, sfilter, caseInsensitive,
negate_filter=negate)
numhits += dump_entries(xmldata, needles, sfilter, caseInsensitive,
negate_filter=negate)
else: # Do a search only of types
for ( sfilter, negate ) in searchTypes:
numhits += dump_entries(xmldata, None, sfilter, negate_filter=negate)
/relevation/branches/1.2/debian/changelog
2,7 → 2,7
 
* New version
 
-- Toni Corvera <outlyer@gmail.com> Sat, 08 Dec 2012 00:52:41 +0100
-- Toni Corvera <outlyer@gmail.com> Sat, 21 Oct 2013 00:52:41 +0100
 
relevation (1.1-upstream.1) unstable; urgency=low