]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/blacklist.py
blacklist.py: add read() method too, for completeness
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / blacklist.py
1
2 import os
3
4 from zope.interface import implements
5 from twisted.internet import defer
6 from twisted.python import log as twisted_log
7
8 from allmydata.interfaces import IFileNode, IFilesystemNode
9 from allmydata.util import base32
10 from allmydata.util.encodingutil import quote_output
11
12
13 class FileProhibited(Exception):
14     """This client has been configured to prohibit access to this object."""
15     def __init__(self, reason):
16         Exception.__init__(self, "Access Prohibited: %s" % quote_output(reason, encoding='utf-8', quotemarks=False))
17         self.reason = reason
18
19
20 class Blacklist:
21     def __init__(self, blacklist_fn):
22         self.blacklist_fn = blacklist_fn
23         self.last_mtime = None
24         self.entries = {}
25         self.read_blacklist() # sets .last_mtime and .entries
26
27     def read_blacklist(self):
28         try:
29             current_mtime = os.stat(self.blacklist_fn).st_mtime
30         except EnvironmentError:
31             # unreadable blacklist file means no blacklist
32             self.entries.clear()
33             return
34         try:
35             if self.last_mtime is None or current_mtime > self.last_mtime:
36                 self.entries.clear()
37                 for line in open(self.blacklist_fn, "r").readlines():
38                     line = line.strip()
39                     if not line or line.startswith("#"):
40                         continue
41                     si_s, reason = line.split(None, 1)
42                     si = base32.a2b(si_s) # must be valid base32
43                     self.entries[si] = reason
44                 self.last_mtime = current_mtime
45         except Exception, e:
46             twisted_log.err(e, "unparseable blacklist file")
47             raise
48
49     def check_storageindex(self, si):
50         self.read_blacklist()
51         reason = self.entries.get(si, None)
52         if reason is not None:
53             # log this to logs/twistd.log, since web logs go there too
54             twisted_log.msg("blacklist prohibited access to SI %s: %s" %
55                             (base32.b2a(si), reason))
56         return reason
57
58
59 class ProhibitedNode:
60     implements(IFileNode)
61
62     def __init__(self, wrapped_node, reason):
63         assert IFilesystemNode.providedBy(wrapped_node), wrapped_node
64         self.wrapped_node = wrapped_node
65         self.reason = reason
66
67     def get_cap(self):
68         return self.wrapped_node.get_cap()
69
70     def get_readcap(self):
71         return self.wrapped_node.get_readcap()
72
73     def is_readonly(self):
74         return self.wrapped_node.is_readonly()
75
76     def is_mutable(self):
77         return self.wrapped_node.is_mutable()
78
79     def is_unknown(self):
80         return self.wrapped_node.is_unknown()
81
82     def is_allowed_in_immutable_directory(self):
83         return self.wrapped_node.is_allowed_in_immutable_directory()
84
85     def is_alleged_immutable(self):
86         return self.wrapped_node.is_alleged_immutable()
87
88     def raise_error(self):
89         # We don't raise an exception here because that would prevent the node from being listed.
90         pass
91
92     def get_uri(self):
93         return self.wrapped_node.get_uri()
94
95     def get_write_uri(self):
96         return self.wrapped_node.get_write_uri()
97
98     def get_readonly_uri(self):
99         return self.wrapped_node.get_readonly_uri()
100
101     def get_storage_index(self):
102         return self.wrapped_node.get_storage_index()
103
104     def get_verify_cap(self):
105         return self.wrapped_node.get_verify_cap()
106
107     def get_repair_cap(self):
108         return self.wrapped_node.get_repair_cap()
109
110     def get_size(self):
111         return None
112
113     def get_current_size(self):
114         return defer.succeed(None)
115
116     def get_size_of_best_version(self):
117         return defer.succeed(None)
118
119     def check(self, monitor, verify, add_lease):
120         return defer.succeed(None)
121
122     def check_and_repair(self, monitor, verify, add_lease):
123         return defer.succeed(None)
124
125     def get_version(self):
126         return None
127
128     # Omitting any of these methods would fail safe; they are just to ensure correct error reporting.
129
130     def get_best_readable_version(self):
131         raise FileProhibited(self.reason)
132
133     def download_best_version(self):
134         raise FileProhibited(self.reason)
135
136     def get_best_mutable_version(self):
137         raise FileProhibited(self.reason)
138
139     def overwrite(self, new_contents):
140         raise FileProhibited(self.reason)
141
142     def modify(self, modifier_cb):
143         raise FileProhibited(self.reason)
144
145     def get_servermap(self, mode):
146         raise FileProhibited(self.reason)
147
148     def download_version(self, servermap, version):
149         raise FileProhibited(self.reason)
150
151     def upload(self, new_contents, servermap):
152         raise FileProhibited(self.reason)
153
154     def get_writekey(self):
155         raise FileProhibited(self.reason)
156
157     def read(self, consumer, offset=0, size=None):
158         raise FileProhibited(self.reason)