Move EncryptedTemporaryFile from SFTP frontend to allmydata.util.fileutil, and make...
authordavid-sarah <david-sarah@jacaranda.org>
Sun, 11 Jul 2010 21:37:21 +0000 (14:37 -0700)
committerdavid-sarah <david-sarah@jacaranda.org>
Sun, 11 Jul 2010 21:37:21 +0000 (14:37 -0700)
src/allmydata/frontends/ftpd.py
src/allmydata/frontends/sftpd.py
src/allmydata/util/fileutil.py

index 8e66e43738dff7f3244aec7ebc1aa103f89fd782..1321863af9ff8d385835bcab1eac3d5a7ea4d064 100644 (file)
@@ -1,5 +1,4 @@
 
-import tempfile
 from zope.interface import implements
 from twisted.application import service, strports
 from twisted.internet import defer
@@ -10,6 +9,7 @@ from twisted.protocols import ftp
 from allmydata.interfaces import IDirectoryNode, ExistingChildError, \
      NoSuchChildError
 from allmydata.immutable.upload import FileHandle
+from allmydata.util.fileutil import EncryptedTemporaryFile
 
 class ReadFile:
     implements(ftp.IReadFile)
@@ -27,7 +27,7 @@ class FileWriter:
             raise NotImplementedError("Non-streaming producer not supported.")
         # we write the data to a temporary file, since Tahoe can't do
         # streaming upload yet.
-        self.f = tempfile.TemporaryFile()
+        self.f = EncryptedTemporaryFile()
         return None
 
     def unregisterProducer(self):
index 5980effb96c6fea18a71cfb17c29ac0b5cadddf4..a38196fcf295fa8be6a186a924bec4acc86cc1a3 100644 (file)
@@ -1,5 +1,5 @@
 
-import os, tempfile, heapq, binascii, traceback, array, stat, struct
+import heapq, traceback, array, stat, struct
 from types import NoneType
 from stat import S_IFREG, S_IFDIR
 from time import time, strftime, localtime
@@ -32,8 +32,7 @@ from allmydata.interfaces import IFileNode, IDirectoryNode, ExistingChildError,
 from allmydata.mutable.common import NotWriteableError
 from allmydata.immutable.upload import FileHandle
 from allmydata.dirnode import update_metadata
-
-from pycryptopp.cipher.aes import AES
+from allmydata.util.fileutil import EncryptedTemporaryFile
 
 noisy = True
 use_foolscap_logging = True
@@ -288,56 +287,6 @@ def _direntry_for(filenode_or_parent, childname, filenode=None):
     return None
 
 
-class EncryptedTemporaryFile(PrefixingLogMixin):
-    # not implemented: next, readline, readlines, xreadlines, writelines
-
-    def __init__(self):
-        PrefixingLogMixin.__init__(self, facility="tahoe.sftp")
-        self.file = tempfile.TemporaryFile()
-        self.key = os.urandom(16)  # AES-128
-
-    def _crypt(self, offset, data):
-        # TODO: use random-access AES (pycryptopp ticket #18)
-        offset_big = offset // 16
-        offset_small = offset % 16
-        iv = binascii.unhexlify("%032x" % offset_big)
-        cipher = AES(self.key, iv=iv)
-        cipher.process("\x00"*offset_small)
-        return cipher.process(data)
-
-    def close(self):
-        self.file.close()
-
-    def flush(self):
-        self.file.flush()
-
-    def seek(self, offset, whence=0):  # 0 = SEEK_SET
-        if noisy: self.log(".seek(%r, %r)" % (offset, whence), level=NOISY)
-        self.file.seek(offset, whence)
-
-    def tell(self):
-        offset = self.file.tell()
-        if noisy: self.log(".tell() = %r" % (offset,), level=NOISY)
-        return offset
-
-    def read(self, size=-1):
-        if noisy: self.log(".read(%r)" % (size,), level=NOISY)
-        index = self.file.tell()
-        ciphertext = self.file.read(size)
-        plaintext = self._crypt(index, ciphertext)
-        return plaintext
-
-    def write(self, plaintext):
-        if noisy: self.log(".write(<data of length %r>)" % (len(plaintext),), level=NOISY)
-        index = self.file.tell()
-        ciphertext = self._crypt(index, plaintext)
-        self.file.write(ciphertext)
-
-    def truncate(self, newsize):
-        if noisy: self.log(".truncate(%r)" % (newsize,), level=NOISY)
-        self.file.truncate(newsize)
-
-
 class OverwriteableFileConsumer(PrefixingLogMixin):
     implements(IFinishableConsumer)
     """I act both as a consumer for the download of the original file contents, and as a
index 46e1c9bfeafd47f351d4852846381a4911f0826e..f671f7eade61ada89cbdf9785e0eb1b1a0d6c0cc 100644 (file)
@@ -2,10 +2,13 @@
 Futz with files like a pro.
 """
 
-import sys, exceptions, os, stat, tempfile, time
+import sys, exceptions, os, stat, tempfile, time, binascii
 
 from twisted.python import log
 
+from pycryptopp.cipher.aes import AES
+
+
 def rename(src, dst, tries=4, basedelay=0.1):
     """ Here is a superkludge to workaround the fact that occasionally on
     Windows some other process (e.g. an anti-virus scanner, a local search
@@ -112,6 +115,49 @@ class NamedTemporaryDirectory:
         if self.cleanup and hasattr(self, 'name'):
             rm_dir(self.name)
 
+class EncryptedTemporaryFile:
+    # not implemented: next, readline, readlines, xreadlines, writelines
+
+    def __init__(self):
+        self.file = tempfile.TemporaryFile()
+        self.key = os.urandom(16)  # AES-128
+
+    def _crypt(self, offset, data):
+        offset_big = offset // 16
+        offset_small = offset % 16
+        iv = binascii.unhexlify("%032x" % offset_big)
+        cipher = AES(self.key, iv=iv)
+        cipher.process("\x00"*offset_small)
+        return cipher.process(data)
+
+    def close(self):
+        self.file.close()
+
+    def flush(self):
+        self.file.flush()
+
+    def seek(self, offset, whence=0):  # 0 = SEEK_SET
+        self.file.seek(offset, whence)
+
+    def tell(self):
+        offset = self.file.tell()
+        return offset
+
+    def read(self, size=-1):
+        index = self.file.tell()
+        ciphertext = self.file.read(size)
+        plaintext = self._crypt(index, ciphertext)
+        return plaintext
+
+    def write(self, plaintext):
+        index = self.file.tell()
+        ciphertext = self._crypt(index, plaintext)
+        self.file.write(ciphertext)
+
+    def truncate(self, newsize):
+        self.file.truncate(newsize)
+
+
 def make_dirs(dirname, mode=0777):
     """
     An idempotent version of os.makedirs().  If the dir already exists, do