X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb-python/blobdiff_plain/f845cee4f9afa3b1591a3bef4787bb381acd6473..3200c805f073fc4a480fbbd1345c09d03f4efae4:/catacomb/pwsafe.py diff --git a/catacomb/pwsafe.py b/catacomb/pwsafe.py index bc8c038..31df641 100644 --- a/catacomb/pwsafe.py +++ b/catacomb/pwsafe.py @@ -35,6 +35,22 @@ from cStringIO import StringIO as _StringIO import catacomb as _C ###-------------------------------------------------------------------------- +### Python version portability. + +def _iterkeys(dict): return dict.iterkeys() +def _itervalues(dict): return dict.itervalues() +def _iteritems(dict): return dict.iteritems() + +def _bin(text): return text +def _text(bin): return bin + +_NUL = _bin('\0') +_CIPHER = _bin('cipher:') +_MAC = _bin('mac:') + +def _excval(): return SYS.exc_info()[1] + +###-------------------------------------------------------------------------- ### Text encoding utilities. def _literalp(s): @@ -183,10 +199,10 @@ class PPK (Crypto): keys, indicating that a salt should be chosen randomly. """ if not salt: salt = _C.rand.block(h.hashsz) - tag = '%s\0%s' % (pp, salt) + tag = pp + _NUL + salt Crypto.__init__(me, c, h, m, - h().hash('cipher:' + tag).done(), - h().hash('mac:' + tag).done()) + h().hash(_CIPHER).hash(tag).done(), + h().hash(_MAC).hash(tag).done()) me.salt = salt ###-------------------------------------------------------------------------- @@ -308,7 +324,7 @@ class StorageBackend (object): @staticmethod def classes(): """Return an iterator over the concrete subclasses.""" - return StorageBackend.CLASSES.itervalues() + return _itervalues(StorageBackend.CLASSES) @staticmethod def open(file, writep = False): @@ -339,9 +355,9 @@ class StorageBackend (object): `_open' method, which is invoked in the usual case. """ super(StorageBackend, me).__init__(*args, **kw) - if me.NAME is None: raise ValueError, 'abstract class' + if me.NAME is None: raise ValueError('abstract class') if _magic is not None: _magic(me) - elif file is None: raise ValueError, 'missing file parameter' + elif file is None: raise ValueError('missing file parameter') else: me._open(file, writep) me._writep = writep me._livep = True @@ -361,12 +377,12 @@ class StorageBackend (object): def _check_live(me): """Raise an error if the receiver has been closed.""" - if not me._livep: raise ValueError, 'database is closed' + if not me._livep: raise ValueError('database is closed') def _check_write(me): """Raise an error if the receiver is not open for writing.""" me._check_live() - if not me._writep: raise ValueError, 'database is read-only' + if not me._writep: raise ValueError('database is read-only') def _check_meta_name(me, name): """ @@ -376,7 +392,7 @@ class StorageBackend (object): password storage. """ if name.startswith('$'): - raise ValueError, "invalid metadata key `%s'" % name + raise ValueError("invalid metadata key `%s'" % name) ## Context protocol. @@ -403,7 +419,7 @@ class StorageBackend (object): me._check_meta_name(name) me._check_live() value = me._get_meta(name, default) - if value is StorageBackend.FAIL: raise KeyError, name + if value is StorageBackend.FAIL: raise KeyError(name) return value def put_meta(me, name, value): @@ -501,7 +517,7 @@ else: def _open(me, file, writep): try: me._db = _G.open(file, writep and 'w' or 'r') - except _G.error, e: raise StorageBackendRefusal, e + except _G.error: raise StorageBackendRefusal(_excval()) def _create(me, file): me._db = _G.open(file, 'n', 0600) @@ -564,13 +580,12 @@ else: ver = me._query_scalar( "SELECT value FROM meta WHERE name = '$version'", "version check") - except (_Q.DatabaseError, _Q.OperationalError), e: - raise StorageBackendRefusal, e - if ver is None: raise ValueError, 'database broken (missing $version)' + except (_Q.DatabaseError, _Q.OperationalError): + raise StorageBackendRefusal(_excval()) + if ver is None: raise ValueError('database broken (missing $version)') elif ver < me.VERSION: me._upgrade(ver) - elif ver > me.VERSION: - raise ValueError, 'unknown database schema version (%d > %d)' % \ - (ver, me.VERSION) + elif ver > me.VERSION: raise ValueError \ + ('unknown database schema version (%d > %d)' % (ver, me.VERSION)) def _create(me, file): fd = _OS.open(file, _OS.O_WRONLY | _OS.O_CREAT | _OS.O_EXCL, 0600) @@ -611,7 +626,7 @@ else: else: val, = row try: row = next(c) except StopIteration: pass - else: raise ValueError, 'multiple matching records for %s' % what + else: raise ValueError('multiple matching records for %s' % what) return val def _query_scalar(me, query, what, default = None, args = []): @@ -634,7 +649,7 @@ else: def _del_meta(me, name): c = me._db.cursor() c.execute("DELETE FROM meta WHERE name = ?", [name]) - if not c.rowcount: raise KeyError, name + if not c.rowcount: raise KeyError(name) def _iter_meta(me): c = me._db.cursor() @@ -645,7 +660,7 @@ else: pld = me._query_scalar("SELECT payload FROM passwd WHERE label = ?", "password", default = None, args = [buffer(label)]) - if pld is None: raise KeyError, label + if pld is None: raise KeyError(label) return str(pld) def _put_passwd(me, label, payload): @@ -657,7 +672,7 @@ else: def _del_passwd(me, label): c = me._db.cursor() c.execute("DELETE FROM passwd WHERE label = ?", [label]) - if not c.rowcount: raise KeyError, label + if not c.rowcount: raise KeyError(label) def _iter_passwds(me): c = me._db.cursor() @@ -790,7 +805,7 @@ class PlainTextBackend (StorageBackend): def _write_meta(me, f, prefix = ''): """Write the metadata records to F, each with the given PREFIX.""" f.write('\n## Metadata.\n') - for k, v in me._meta.iteritems(): + for k, v in _iteritems(me._meta): f.write('%s%s=%s\n' % (prefix, _enc_metaname(k), _enc_metaval(v))) def _get_meta(me, name, default): @@ -802,7 +817,7 @@ class PlainTextBackend (StorageBackend): me._mark_dirty() del me._meta[name] def _iter_meta(me): - return me._meta.iteritems() + return _iteritems(me._meta) def _parse_passwd(me, line): """Parse LINE as a password LABEL=PAYLOAD pair, and updates `_pw'.""" @@ -812,7 +827,7 @@ class PlainTextBackend (StorageBackend): def _write_passwd(me, f, prefix = ''): """Write the password records to F, each with the given PREFIX.""" f.write('\n## Password data.\n') - for k, v in me._pw.iteritems(): + for k, v in _iteritems(me._pw): f.write('%s%s=%s\n' % (prefix, _b64(k), _b64(v))) def _get_passwd(me, label): @@ -824,7 +839,7 @@ class PlainTextBackend (StorageBackend): me._mark_dirty() del me._pw[str(label)] def _iter_passwds(me): - return me._pw.iteritems() + return _iteritems(me._pw) class FlatFileStorageBackend (PlainTextBackend): """ @@ -927,8 +942,8 @@ class DirectoryStorageBackend (PlainTextBackend): def _get_passwd(me, label): try: f = open(me._pwfile(label), 'rb') - except (OSError, IOError), e: - if e.errno == _E.ENOENT: raise KeyError, label + except (OSError, IOError): + if _excval().errno == _E.ENOENT: raise KeyError(label) else: raise with f: return f.read() def _put_passwd(me, label, payload): @@ -940,8 +955,8 @@ class DirectoryStorageBackend (PlainTextBackend): def _del_passwd(me, label): try: _OS.remove(me._pwfile(label)) - except (OSError, IOError), e: - if e.errno == _E.ENOENT: raise KeyError, label + except (OSError, IOError): + if _excval().errno == _E.ENOENT: raise KeyError(label) else: raise def _iter_passwds(me): pw = _OS.path.join(me._dir, 'pw') @@ -1014,7 +1029,7 @@ class PW (object): raise me.ck = b.getblk16() me.mk = b.getblk16() - if not b.endp: raise ValueError, 'trailing junk' + if not b.endp: raise ValueError('trailing junk') ## Set the key, and stash it and the tag-hashing secret. me.k = Crypto(c, h, m, me.ck, me.mk) @@ -1092,7 +1107,7 @@ class PW (object): def __getitem__(me, key): """Return the password for the given KEY.""" try: return me.unpack(me.db.get_passwd(me.keyxform(key)))[1] - except KeyError: raise KeyError, key + except KeyError: raise KeyError(key) def __setitem__(me, key, value): """Associate the password VALUE with the KEY.""" @@ -1101,7 +1116,7 @@ class PW (object): def __delitem__(me, key): """Forget all about the KEY.""" try: me.db.del_passwd(me.keyxform(key)) - except KeyError: raise KeyError, key + except KeyError: raise KeyError(key) def __iter__(me): """Iterate over the known password tags."""