2014-05-05 19:47:20 +02:00
|
|
|
|
|
|
|
import os
|
|
|
|
import gnupg
|
|
|
|
from binascii import hexlify
|
|
|
|
import errno
|
|
|
|
import logging
|
|
|
|
|
|
|
|
log = logging.getLogger('gpgfs')
|
|
|
|
|
2014-05-18 11:34:46 +02:00
|
|
|
FMT_GPG = 0
|
|
|
|
|
2014-05-05 19:47:20 +02:00
|
|
|
class GpgStore(object):
|
|
|
|
def __init__(self, encroot, keyid):
|
|
|
|
self.encroot = encroot
|
|
|
|
self.keyid = keyid
|
|
|
|
self.gpg = gnupg.GPG()
|
|
|
|
|
2014-05-18 11:34:46 +02:00
|
|
|
def put(self, data, path=None, format=FMT_GPG):
|
|
|
|
assert format == FMT_GPG
|
2014-05-05 19:47:20 +02:00
|
|
|
if not path:
|
2015-12-08 00:15:47 +01:00
|
|
|
path = hexlify(os.urandom(20)).decode('utf-8')
|
2014-05-05 19:47:20 +02:00
|
|
|
path = path[:2] + '/' + path[2:]
|
2014-05-18 11:36:22 +02:00
|
|
|
encdir = self.encroot + '/' + path[:2]
|
|
|
|
if not os.path.exists(encdir):
|
2015-12-08 00:15:47 +01:00
|
|
|
os.mkdir(encdir, 0o755)
|
2014-05-05 19:47:20 +02:00
|
|
|
res = self.gpg.encrypt(data, self.keyid, armor=False)
|
|
|
|
if not res.ok:
|
|
|
|
log.error("encryption failed (keyid %s), %s: %s",
|
|
|
|
self.keyid, res.status, path)
|
|
|
|
raise OSError(errno.EIO)
|
|
|
|
try:
|
2015-12-08 00:15:47 +01:00
|
|
|
with open(self.encroot + '/' + path + '.tmp', 'wb') as fd:
|
2014-05-05 19:47:20 +02:00
|
|
|
fd.write(res.data)
|
|
|
|
os.rename(self.encroot + '/' + path + '.tmp',
|
|
|
|
self.encroot + '/' + path)
|
2015-12-08 00:15:47 +01:00
|
|
|
except IOError as err:
|
2014-05-05 19:47:20 +02:00
|
|
|
log.error("write failed: %s: %s", path, str(err))
|
|
|
|
raise OSError(err.errno)
|
|
|
|
finally:
|
|
|
|
try: os.remove(self.encroot + '/' + path + '.tmp')
|
|
|
|
except: pass
|
|
|
|
log.debug('encrypted %s' % path)
|
|
|
|
return path
|
|
|
|
|
2014-05-18 11:34:46 +02:00
|
|
|
def get(self, path, format=FMT_GPG):
|
|
|
|
assert format == FMT_GPG
|
2014-05-05 19:47:20 +02:00
|
|
|
try:
|
2015-12-08 00:15:47 +01:00
|
|
|
data = open(self.encroot + '/' + path, 'rb').read()
|
|
|
|
except OSError as err:
|
2014-05-05 19:47:20 +02:00
|
|
|
log.error("read failed: %s: %s", path, str(err))
|
|
|
|
raise
|
|
|
|
if not data:
|
|
|
|
return data
|
|
|
|
res = self.gpg.decrypt(data)
|
|
|
|
if not res.ok:
|
|
|
|
log.error("decryption failed, %s: %s", res.status, path)
|
|
|
|
raise OSError(errno.EIO)
|
|
|
|
log.debug('decrypted %s' % path)
|
2015-12-08 00:15:47 +01:00
|
|
|
return res.data
|
2014-05-05 19:47:20 +02:00
|
|
|
|
|
|
|
def delete(self, path):
|
|
|
|
os.remove(self.encroot + '/' + path)
|
2014-05-18 11:40:07 +02:00
|
|
|
if len(path) >= 3 and path[2] == '/':
|
|
|
|
try:
|
|
|
|
os.rmdir(self.encroot + '/' + path[:2])
|
|
|
|
except OSError:
|
|
|
|
pass
|
2014-05-05 19:47:20 +02:00
|
|
|
log.debug('deleted %s' % path)
|
2014-05-14 21:35:58 +02:00
|
|
|
|
|
|
|
def exists(self, path):
|
|
|
|
return os.path.exists(self.encroot + '/' + path)
|