Subversion Repositories pub

Compare Revisions

No changes between revisions

Ignore whitespace Rev 123 → Rev 122

/relevation/branches/0.2/relevation.py
File deleted
Property changes:
Deleted: svn:executable
Deleted: svn:keywords
-Rev Id Date
\ No newline at end of property
/relevation/branches/0.2/Makefile
File deleted
/relevation/branches/0.2/CHANGELOG
1,10 → 1,8
0.2.0 (2011-06-27) (unreleased)
0.2.0 (2011-06-26) (unreleased)
- Allow multiple queries in one run
- Consider positional arguments as queries
- Feedback enhancements
- Added Makefile for installation
- Added --help and --version
 
0.1.0 (2011-06-24) (internal)
0.1.0 (2011-06-24) (unreleased)
- Initial proof of concept
 
/relevation/branches/0.2/relevation
0,0 → 1,166
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
 
import getopt
import libxml2
import os
import sys
import zlib
from Crypto.Cipher import AES
 
"""
Relevation Password Printer
a command line interface to Revelation Password Manager
 
Code based on Revelation's former BTS (no longer online, not archived?):
(ref1) code:
http://oss.wired-networks.net/bugzilla/attachment.cgi?id=13&action=view
(ref2) bug report:
http://oss.wired-networks.net/bugzilla/show_bug.cgi?id=111
-> http://web.archive.org/http://oss.wired-networks.net/bugzilla/show_bug.cgi?id=111
(ref3) http://docs.python.org/library/zlib.html
"""
 
__author__ = 'Toni Corvera'
__date__ = '$Date$'
__revision__ = '$Rev$'
__version_info__ = ( 0, 2, 0 )
__version__ = '.'.join(map(str, __version_info__))
RELEASE=True
 
def usage(channel):
def p(s):
channel.write(s)
p('%s {-f passwordfile} {-p password | -0} search [search2] [search3]\n')
p('\n')
p(' -f <FILE>, --file=<FILE> Revelation password file\n')
p(' -p <PASS>, --password=<PASS> Master password\n')
p(' -s <STRING>, --search=<STRING> Search for string\n')
p(' -i, --case-insensitive Case insensitive search [default]\n')
p(' -c, --case-sensitive Case sensitive search\n')
p(' -0, --stdin Read password from standard input\n')
# p(' -a, --ask Ask password interactively\n')
p('\n')
 
def search(xmldata, search, caseInsensitive=True):
doc = libxml2.parseDoc(xmldata)
ctxt = doc.xpathNewContext()
commonXPath = '//revelationdata//entry[@type!="folder"]//text()'
caseSensitiveXPath = '[contains(., "%s")]/../..' % search
caseInsensitiveXPath = '[contains(translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz"), "%s")]/../..' % search
if caseInsensitive:
xpath = commonXPath + caseInsensitiveXPath
else:
xpath = commonXPath + caseSensitiveXPath
res = ctxt.xpathEval(xpath)
print '-> Search "%s": ' % search,
if not len(res):
print 'No matches'
sys.exit(2)
print '%d matches' % len(res)
tagnames ={ 'generic-url': 'Url:',
'generic-username': 'Username:',
'generic-password': 'Password:',
'generic-email': 'Email:',
'generic-hostname': 'Hostname:',
}
for x in res:
print '- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - '
print ''
for attr in x.properties: # Is it accessible directly?
if attr.name == 'type':
print 'Type:',attr.children
for chld in x.children:
n = chld.name
val = chld.content
if n == 'name':
print 'Name:',val
elif n == 'description':
print 'Description:',val
elif n == 'field':
for attr in chld.properties:
if attr.name == 'id':
idv = attr.content
if idv in tagnames:
idv = tagnames[idv]
print idv,chld.content
print ''
# for chld in x.children
sys.stderr.write('<- (end of %d results for "%s")\n\n' % ( len(res), search ))
doc.freeDoc()
ctxt.xpathFreeContext()
 
 
def main():
datafile = None
password = None
searches = []
caseInsensitive = True
 
sys.stderr.write('Relevation v%s, (c) 2011 Toni Corvera\n\n' % __version__)
try:
ops, args = getopt.getopt(sys.argv[1:], 'f:p:s:0ci',
[ 'file=', 'password=', 'search=', 'stdin',
'case-sensitive', 'case-insensitive' ])
except getopt.GetoptError, err:
print str(err)
usage(sys.stderr)
sys.exit(os.EX_USAGE)
if args:
searches = args
 
for opt, arg in ops:
if opt in ( '-f', '--file' ):
datafile = arg
elif opt in ( '-p', '--password' ):
password = arg
elif opt in ( '-0', '--stdin' ):
sys.stderr.write('Getting password from stdin\n')
p = sys.stdin.readline()
p = p[:-1]
elif opt in ( '-s', '--search' ):
searches.append(arg)
elif opt in ( '-i', '--case-insensitive' ):
caseInsensitive = True
elif opt in ( '-c', '--case-sensitive' ):
caseInsensitive = False
else:
assert False, "internal error parsing options"
if not datafile or not password:
usage(sys.stderr)
sys.exit(os.EX_USAGE)
# Encrypted data
try:
f = open(datafile, "rb")
data = f.read()
finally:
f.close()
# Pad password
password += (chr(0) * (32 - len(password)))
# Data IV
c = AES.new(password)
iv = c.decrypt(data[12:28])
# Decrypt. Decrypted data is compressed
c = AES.new(password, AES.MODE_CBC, iv)
cleardata_gz = c.decrypt(data[28:])
# Length of data padding
padlen = ord(cleardata_gz[-1])
# Decompress actual data (15 is wbits [ref3] DON'T CHANGE, 2**15 is the (initial) buf size)
xmldata = zlib.decompress(cleardata_gz[:-padlen], 15, 2**15)
if not searches:
print xmldata
sys.exit(os.EX_OK)
for s in searches:
search(xmldata, s, caseInsensitive)
 
if __name__ == '__main__':
try:
main()
except libxml2.parserError as e:
sys.stderr.write('XML parsing error\n')
if not RELEASE:
import traceback
traceback.print_exc()
sys.exit(os.EX_DATAERR)
 
# vim:set ts=4 et ai fileencoding=utf-8: #
Property changes:
Added: svn:executable
Added: svn:keywords
+Rev Id Date
\ No newline at end of property