Subversion Repositories pub

Compare Revisions

No changes between revisions

Ignore whitespace Rev 116 → Rev 117

/relevation/tags/0.1.0/relevation
0,0 → 1,142
#!/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?):
(1) code:
http://oss.wired-networks.net/bugzilla/attachment.cgi?id=13&action=view
(2) 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
"""
 
__author__ = 'Toni Corvera'
__date__ = '$Date$'
__revision__ = '$Rev$'
__version_info__ = ( 0, 1, 0 )
__version__ = '.'.join(map(str, __version_info__))
 
def usage(channel):
def p(s):
channel.write(s)
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 main():
datafile = None
password = None
search = None
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)
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' ):
search = 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)
# read data from file
f = open(datafile, "rb")
data = f.read()
f.close()
# pad the password
password += (chr(0) * (32 - len(password)))
# get the IV
c = AES.new(password)
iv = c.decrypt(data[12:28])
# decrypt the data
c = AES.new(password, AES.MODE_CBC, iv)
rawdata = c.decrypt(data[28:])
# fetch padlen, and decompress data
padlen = ord(rawdata[-1])
xmldata = zlib.decompress(rawdata[:-padlen], 15, 32768)
if not search:
print xmldata
sys.exit(os.EX_OK)
 
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)
if not len(res):
sys.stderr.write('No matches\n')
sys.exit(2)
print '%d matches:' % len(res)
tagnames ={ 'generic-url': 'Url:',
'generic-username': 'Username:',
'generic-password': 'Password:',
}
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
doc.freeDoc()
ctxt.xpathFreeContext()
 
 
if __name__ == '__main__':
main()
 
# vim:set ts=4 et ai fileencoding=utf-8: #
Property changes:
Added: svn:executable