Ticket #1083: make-ftp-use-encrypted-temporary-file.dpatch

File make-ftp-use-encrypted-temporary-file.dpatch, 10.7 KB (added by davidsarah, at 2010-07-17T06:02:25Z)

Move EncryptedTemporaryFile? from SFTP frontend to allmydata.util.fileutil, and make the FTP frontend also use it (fi xing #1083). Also, docstrings for non-obvious usage restrictions on methods of EncryptedTemporaryFile?.

Line 
1Sun Jul 11 22:37:21 GMT Daylight Time 2010  david-sarah@jacaranda.org
2  * Move EncryptedTemporaryFile from SFTP frontend to allmydata.util.fileutil, and make the FTP frontend also use it (fixing #1083).
3
4Sat Jul 17 06:46:47 GMT Daylight Time 2010  david-sarah@jacaranda.org
5  * fileutil: docstrings for non-obvious usage restrictions on methods of EncryptedTemporaryFile.
6
7New patches:
8
9[Move EncryptedTemporaryFile from SFTP frontend to allmydata.util.fileutil, and make the FTP frontend also use it (fixing #1083).
10david-sarah@jacaranda.org**20100711213721
11 Ignore-this: e452e8ca66391aa2a1a49afe0114f317
12] {
13hunk ./src/allmydata/frontends/ftpd.py 2
14 
15-import tempfile
16 from zope.interface import implements
17 from twisted.application import service, strports
18 from twisted.internet import defer
19hunk ./src/allmydata/frontends/ftpd.py 12
20 from allmydata.interfaces import IDirectoryNode, ExistingChildError, \
21      NoSuchChildError
22 from allmydata.immutable.upload import FileHandle
23+from allmydata.util.fileutil import EncryptedTemporaryFile
24 
25 class ReadFile:
26     implements(ftp.IReadFile)
27hunk ./src/allmydata/frontends/ftpd.py 30
28             raise NotImplementedError("Non-streaming producer not supported.")
29         # we write the data to a temporary file, since Tahoe can't do
30         # streaming upload yet.
31-        self.f = tempfile.TemporaryFile()
32+        self.f = EncryptedTemporaryFile()
33         return None
34 
35     def unregisterProducer(self):
36hunk ./src/allmydata/frontends/sftpd.py 2
37 
38-import os, tempfile, heapq, binascii, traceback, array, stat, struct
39+import heapq, traceback, array, stat, struct
40 from types import NoneType
41 from stat import S_IFREG, S_IFDIR
42 from time import time, strftime, localtime
43hunk ./src/allmydata/frontends/sftpd.py 35
44 from allmydata.mutable.common import NotWriteableError
45 from allmydata.immutable.upload import FileHandle
46 from allmydata.dirnode import update_metadata
47-
48-from pycryptopp.cipher.aes import AES
49+from allmydata.util.fileutil import EncryptedTemporaryFile
50 
51 noisy = True
52 use_foolscap_logging = True
53hunk ./src/allmydata/frontends/sftpd.py 290
54     return None
55 
56 
57-class EncryptedTemporaryFile(PrefixingLogMixin):
58-    # not implemented: next, readline, readlines, xreadlines, writelines
59-
60-    def __init__(self):
61-        PrefixingLogMixin.__init__(self, facility="tahoe.sftp")
62-        self.file = tempfile.TemporaryFile()
63-        self.key = os.urandom(16)  # AES-128
64-
65-    def _crypt(self, offset, data):
66-        # TODO: use random-access AES (pycryptopp ticket #18)
67-        offset_big = offset // 16
68-        offset_small = offset % 16
69-        iv = binascii.unhexlify("%032x" % offset_big)
70-        cipher = AES(self.key, iv=iv)
71-        cipher.process("\x00"*offset_small)
72-        return cipher.process(data)
73-
74-    def close(self):
75-        self.file.close()
76-
77-    def flush(self):
78-        self.file.flush()
79-
80-    def seek(self, offset, whence=0):  # 0 = SEEK_SET
81-        if noisy: self.log(".seek(%r, %r)" % (offset, whence), level=NOISY)
82-        self.file.seek(offset, whence)
83-
84-    def tell(self):
85-        offset = self.file.tell()
86-        if noisy: self.log(".tell() = %r" % (offset,), level=NOISY)
87-        return offset
88-
89-    def read(self, size=-1):
90-        if noisy: self.log(".read(%r)" % (size,), level=NOISY)
91-        index = self.file.tell()
92-        ciphertext = self.file.read(size)
93-        plaintext = self._crypt(index, ciphertext)
94-        return plaintext
95-
96-    def write(self, plaintext):
97-        if noisy: self.log(".write(<data of length %r>)" % (len(plaintext),), level=NOISY)
98-        index = self.file.tell()
99-        ciphertext = self._crypt(index, plaintext)
100-        self.file.write(ciphertext)
101-
102-    def truncate(self, newsize):
103-        if noisy: self.log(".truncate(%r)" % (newsize,), level=NOISY)
104-        self.file.truncate(newsize)
105-
106-
107 class OverwriteableFileConsumer(PrefixingLogMixin):
108     implements(IFinishableConsumer)
109     """I act both as a consumer for the download of the original file contents, and as a
110hunk ./src/allmydata/util/fileutil.py 5
111 Futz with files like a pro.
112 """
113 
114-import sys, exceptions, os, stat, tempfile, time
115+import sys, exceptions, os, stat, tempfile, time, binascii
116 
117 from twisted.python import log
118 
119hunk ./src/allmydata/util/fileutil.py 9
120+from pycryptopp.cipher.aes import AES
121+
122+
123 def rename(src, dst, tries=4, basedelay=0.1):
124     """ Here is a superkludge to workaround the fact that occasionally on
125     Windows some other process (e.g. an anti-virus scanner, a local search
126hunk ./src/allmydata/util/fileutil.py 118
127         if self.cleanup and hasattr(self, 'name'):
128             rm_dir(self.name)
129 
130+class EncryptedTemporaryFile:
131+    # not implemented: next, readline, readlines, xreadlines, writelines
132+
133+    def __init__(self):
134+        self.file = tempfile.TemporaryFile()
135+        self.key = os.urandom(16)  # AES-128
136+
137+    def _crypt(self, offset, data):
138+        offset_big = offset // 16
139+        offset_small = offset % 16
140+        iv = binascii.unhexlify("%032x" % offset_big)
141+        cipher = AES(self.key, iv=iv)
142+        cipher.process("\x00"*offset_small)
143+        return cipher.process(data)
144+
145+    def close(self):
146+        self.file.close()
147+
148+    def flush(self):
149+        self.file.flush()
150+
151+    def seek(self, offset, whence=0):  # 0 = SEEK_SET
152+        self.file.seek(offset, whence)
153+
154+    def tell(self):
155+        offset = self.file.tell()
156+        return offset
157+
158+    def read(self, size=-1):
159+        index = self.file.tell()
160+        ciphertext = self.file.read(size)
161+        plaintext = self._crypt(index, ciphertext)
162+        return plaintext
163+
164+    def write(self, plaintext):
165+        index = self.file.tell()
166+        ciphertext = self._crypt(index, plaintext)
167+        self.file.write(ciphertext)
168+
169+    def truncate(self, newsize):
170+        self.file.truncate(newsize)
171+
172+
173 def make_dirs(dirname, mode=0777):
174     """
175     An idempotent version of os.makedirs().  If the dir already exists, do
176}
177[fileutil: docstrings for non-obvious usage restrictions on methods of EncryptedTemporaryFile.
178david-sarah@jacaranda.org**20100717054647
179 Ignore-this: 46d8fc10782fa8ec2b6c5b168c841943
180] {
181hunk ./src/allmydata/util/fileutil.py 147
182         return offset
183 
184     def read(self, size=-1):
185+        """A read must not follow a write, or vice-versa, without an intervening seek."""
186         index = self.file.tell()
187         ciphertext = self.file.read(size)
188         plaintext = self._crypt(index, ciphertext)
189hunk ./src/allmydata/util/fileutil.py 154
190         return plaintext
191 
192     def write(self, plaintext):
193+        """A read must not follow a write, or vice-versa, without an intervening seek.
194+        If seeking and then writing causes a 'hole' in the file, the contents of the
195+        hole are unspecified."""
196         index = self.file.tell()
197         ciphertext = self._crypt(index, plaintext)
198         self.file.write(ciphertext)
199hunk ./src/allmydata/util/fileutil.py 162
200 
201     def truncate(self, newsize):
202+        """Truncate or extend the file to 'newsize'. If it is extended, the contents after the
203+        old end-of-file are unspecified. The file position after this operation is unspecified."""
204         self.file.truncate(newsize)
205 
206 
207}
208
209Context:
210
211[cli.py: make command descriptions consistently end with a full stop.
212david-sarah@jacaranda.org**20100714014538
213 Ignore-this: 9ee7fa29ca2d1631db4049c2a389a97a
214] 
215[SFTP: address some of the comments in zooko's review (#1106).
216david-sarah@jacaranda.org**20100712025537
217 Ignore-this: c3921638a2d4f1de2a776ae78e4dc37e
218] 
219[docs/logging.txt: note that setting flogging vars might affect tests with race conditions.
220david-sarah@jacaranda.org**20100712050721
221 Ignore-this: fc1609d215fcd5561a57fd1226206f27
222] 
223[test_storage.py: potential fix for failures when logging is enabled.
224david-sarah@jacaranda.org**19700713040546
225 Ignore-this: 5815693a0df3e64c52c3c6b7be2846c7
226] 
227[upcase_since_on_welcome
228terrellrussell@gmail.com**20100708193903] 
229[server_version_on_welcome_page.dpatch.txt
230freestorm77@gmail.com**20100605191721
231 Ignore-this: b450c76dc875f5ac8cca229a666cbd0a
232 
233 
234 - The storage server version is 0 for all storage nodes in the Welcome Page
235 
236 
237] 
238[NEWS: add NEWS snippets about two recent patches
239zooko@zooko.com**20100708162058
240 Ignore-this: 6c9da6a0ad7351a960bdd60f81532899
241] 
242[directory_html_top_banner.dpatch
243freestorm77@gmail.com**20100622205301
244 Ignore-this: 1d770d975e0c414c996564774f049bca
245 
246 The div tag with the link "Return to Welcome page" on the directory.xhtml page is not correct
247 
248] 
249[tahoe_css_toolbar.dpatch
250freestorm77@gmail.com**20100622210046
251 Ignore-this: 5b3ebb2e0f52bbba718a932f80c246c0
252 
253 CSS modification to be correctly diplayed with Internet Explorer 8
254 
255 The links on the top of page directory.xhtml are not diplayed in the same line as display with Firefox.
256 
257] 
258[runnin_test_tahoe_css.dpatch
259freestorm77@gmail.com**20100622214714
260 Ignore-this: e0db73d68740aad09a7b9ae60a08c05c
261 
262 Runnin test for changes in tahoe.css file
263 
264] 
265[runnin_test_directory_xhtml.dpatch
266freestorm77@gmail.com**20100622201403
267 Ignore-this: f8962463fce50b9466405cb59fe11d43
268 
269 Runnin test for diretory.xhtml top banner
270 
271] 
272[stringutils.py: tolerate sys.stdout having no 'encoding' attribute.
273david-sarah@jacaranda.org**20100626040817
274 Ignore-this: f42cad81cef645ee38ac1df4660cc850
275] 
276[quickstart.html: python 2.5 -> 2.6 as recommended version
277david-sarah@jacaranda.org**20100705175858
278 Ignore-this: bc3a14645ea1d5435002966ae903199f
279] 
280[SFTP: don't call .stopProducing on the producer registered with OverwriteableFileConsumer (which breaks with warner's new downloader).
281david-sarah@jacaranda.org**20100628231926
282 Ignore-this: 131b7a5787bc85a9a356b5740d9d996f
283] 
284[docs/how_to_make_a_tahoe-lafs_release.txt: trivial correction, install.html should now be quickstart.html.
285david-sarah@jacaranda.org**20100625223929
286 Ignore-this: 99a5459cac51bd867cc11ad06927ff30
287] 
288[setup: in the Makefile, refuse to upload tarballs unless someone has passed the environment variable "BB_BRANCH" with value "trunk"
289zooko@zooko.com**20100619034928
290 Ignore-this: 276ddf9b6ad7ec79e27474862e0f7d6
291] 
292[trivial: tiny update to in-line comment
293zooko@zooko.com**20100614045715
294 Ignore-this: 10851b0ed2abfed542c97749e5d280bc
295 (I'm actually committing this patch as a test of the new eager-annotation-computation of trac-darcs.)
296] 
297[docs: about.html link to home page early on, and be decentralized storage instead of cloud storage this time around
298zooko@zooko.com**20100619065318
299 Ignore-this: dc6db03f696e5b6d2848699e754d8053
300] 
301[docs: update about.html, especially to have a non-broken link to quickstart.html, and also to comment out the broken links to "for Paranoids" and "for Corporates"
302zooko@zooko.com**20100619065124
303 Ignore-this: e292c7f51c337a84ebfeb366fbd24d6c
304] 
305[TAG allmydata-tahoe-1.7.0
306zooko@zooko.com**20100619052631
307 Ignore-this: d21e27afe6d85e2e3ba6a3292ba2be1
308] 
309Patch bundle hash:
3100b1bde36c9d61d62ac06a2649406c59c725cc48a