-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdpropssl.py
244 lines (220 loc) · 9.97 KB
/
dpropssl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
"""Some functions to import that will automatically handle client-side
SSL encryption/decryption for DProp. Use these in a Python app that's
communicating with DPropMan, and these functions will make the
appropriate signal handlers that you can then register as needed.."""
import httplib
import dpropjson
from urlparse import urlparse
def makeSSLSyncSignalThunk(cell, key, cert):
"""Returns a thunk that can be used on receiving a SyncSignal from
cell. Will attempt to connect to the requested peer using key and
cert if the peer is an SSL peer. The thunk does not create a new
thread, so you may wish to wrap it with a thunk that does."""
# TODO: Still need to fix security of forwarding
# updateCell/updatePeers
# TODO: Forgery keys are nice, but just listening to a cell will
# get you it, so it's not THAT much more nice.
# TODO: This is something of a carte-blanque to forcing GETs to
# arbitrary servers. This should be locked down.
def thunk(referer, peer, etag, peersEtag):
referer = str(referer)
peer = dpropjson.loads(str(peer))
etag = str(etag)
peersEtag = str(peersEtag)
try:
url = urlparse(peer['url'])
if url.scheme == 'http':
h = httplib.HTTPConnection(url.netloc)
elif url.scheme == 'https':
h = httplib.HTTPSConnection(url.netloc,
key_file=key,
cert_file=cert)
# pdebug("Attempting to sync data")
h.request('GET', url.path,
headers={'Referer': referer,
'If-None-Match': etag})
resp = h.getresponse()
if resp.status == httplib.OK:
# Got a response. Time to merge.
# pdebug("Got new data in sync. Merging...")
cell.UpdateSignal(resp.read(), peer['url'],
dbus_interface='edu.mit.csail.dig.DPropMan.Cell')
elif resp.status == httplib.NOT_MODIFIED:
# pdebug("Sync resulted in no new data.")
# Dummy resp.read() to make sure we can reuse h.
resp.read()
else:
# TODO: Handle errors
# pdebug("Unexpected HTTP response!")
pass
# Next, sync peers.
# pdebug("Attempting to sync peers")
h.request('GET', url.path + '/Peers',
headers={'Referer': referer,
'If-None-Match': peersEtag})
# Why do I get a ResponseNotReady error?
# Why are the peers a bad eTag?
resp = h.getresponse()
if resp.status == httplib.OK:
# Got a response. Time to merge.
# pdebug("Got new data in sync. Merging...")
cell.updatePeers(resp.read(),
dbus_interface='edu.mit.csail.dig.DPropMan.Cell')
elif resp.status == httplib.NOT_MODIFIED:
# pdebug("Sync resulted in no new data.")
pass
else:
# TODO: Handle errors
# pdebug("Unexpected HTTP response!")
pass
h.close()
except httplib.HTTPException, exc:
# TODO: Handle exceptions
# pdebug("Caught HTTPException: %s: %s" % (type(exc).__name__,
# str(exc)))
pass
return thunk
def makeSSLSendUpdateSignalThunk(cell, key, cert):
"""Returns a thunk that can be used on receiving a SendUpdateSignal
from cell. Will attempt to connect to the requested peer using
key and cert if the peer is an SSL peer. The thunk does not
create a new thread, so you may wish to wrap it with a thunk that
does."""
# TODO: Do we really want to include the message??? An adversary
# could forge it.
# TODO: This is something of a carte-blanque to forcing PUTs to
# arbitrary servers. This should be locked down.
def thunk(referer, peer, message):
referer = str(referer)
peer = dpropjson.loads(str(peer))
message = str(message)
try:
url = urlparse(peer['url'])
if url.scheme == 'http':
h = httplib.HTTPConnection(url.netloc)
elif url.scheme == 'https':
h = httplib.HTTPSConnection(url.netloc,
key_file=key,
cert_file=cert)
# We don't dpropjson encode here, as the data
# should already be in JSON.
h.request('PUT', url.path,
urllib.urlencode(
{'data': message}),
{'Referer': referer,
'Content-Type':
'application/x-www-form-urlencoded'})
resp = h.getresponse()
if resp.status != httplib.ACCEPTED:
# TODO: Handle errors
# pdebug("Didn't get ACCEPTED response!!")
pass
else:
# pdebug("PeerUpdate was ACCEPTED!!")
pass
h.close()
except httplib.HTTPException, exc:
# TODO: Handle exceptions
# pdebug("Caught HTTPException: %s: %s" % (type(exc).__name__,
# str(exc)))
pass
return thunk
def makeSSLPeerAddSignalThunk(cell, key, cert):
"""Returns a thunk that can be used on receiving a PeerAddSignal
from cell. Will attempt to connect to the requested peer using
key and cert if the peer is an SSL peer. The thunk does not
create a new thread, so you may wish to wrap it with a thunk that
does."""
# TODO: This is something of a carte-blanque to forcing PUTs to
# arbitrary servers. This should be locked down.
# Load the certificate from the cert file.
cf = open(cert, 'r')
cert_text = cf.read()
cf.close()
def thunk(referer, peer):
referer = str(referer)
peer = dpropjson.loads(str(peer))
try:
url = urlparse(peer['url'])
if url.scheme == 'http':
h = httplib.HTTPConnection(url.netloc)
elif url.scheme == 'https':
h = httplib.HTTPSConnection(url.netloc,
key_file=key,
cert_file=cert)
h.request('PUT', url.path + '/Peers',
urllib.urlencode(
{'peer': dpropjson.dumps({'url': referer,
'cert': cert_text})}),
{'Referer': referer,
'Content-Type':
'application/x-www-form-urlencoded'})
resp = h.getresponse()
if resp.status != httplib.OK:
# TODO: Handle errors
# pdebug("Didn't get OK response!!")
pass
else:
# pdebug("PeerAdd was OK!!")
pass
h.close()
except httplib.HTTPException, exc:
# TODO: Handle exceptions
# pdebug("Caught HTTPException: %s: %s" % (type(exc).__name__,
# str(exc)))
pass
return thunk
def makeSSLDoInitSignalThunk(cell, key, cert):
"""Returns a thunk that can be used on receiving a DoInitSignal
from cell. Will attempt to connect to the requested peer using
key and cert if the peer is an SSL peer. The thunk does not
create a new thread, so you may wish to wrap it with a thunk that
does."""
# TODO: This is something of a carte-blanque to forcing PUTs to
# arbitrary servers. This should be locked down.
def thunk(referer, url):
referer = str(referer)
url = str(url)
try:
parsed_url = urlparse(url)
if parsed_url.scheme == 'http':
h = httplib.HTTPConnection(parsed_url.netloc)
elif parsed_url.scheme == 'https':
h = httplib.HTTPSConnection(parsed_url.netloc,
key_file=key,
cert_file=cert)
pdebug("Performing initial data sync.")
h.request('GET', parsed_url.path,
headers={'Referer': referer})
resp = h.getresponse()
if resp.status != httplib.OK:
# TODO: Handle errors
# pdebug("Didn't get OK response!!")
pass
else:
# Send the response out for a local merge.
# pdebug("Performing merge...")
cell.UpdateSignal(resp.read(), url,
dbus_interface='edu.mit.csail.dig.DPropMan.Cell')
# pdebug("Performing initial peers sync.")
h.request('GET', parsed_url.path + '/Peers',
headers={'Referer': referer})
resp = h.getresponse()
if resp.status != httplib.OK:
# TODO: Handle errors
# pdebug("Didn't get OK response!!")
pass
else:
# pdebug("Merging peers...")
# Add the peer we connect to before the update.
# self.peers[str(url)] = {'cert': False, 'url': str(url)}
cell.updatePeers(resp.read(),
dbus_interface='edu.mit.csail.dig.DPropMan.Cell')
h.close()
except httplib.HTTPException, exc:
# TODO: Handle exceptions
# e.g. BadStatusError, which might happen when crossing HTTPS and HTTP
# pdebug("Caught HTTPException: %s: %s" % (type(exc).__name__,
# str(exc)))
pass
return thunk