auto-close Channel (with a "mood") upon server or crypto error
This commit is contained in:
parent
0748647049
commit
a881d6055f
|
@ -117,7 +117,8 @@ class Channel:
|
||||||
# short timeout and ignore failures
|
# short timeout and ignore failures
|
||||||
requests.post(self._relay_url+"deallocate", data=data,
|
requests.post(self._relay_url+"deallocate", data=data,
|
||||||
timeout=5)
|
timeout=5)
|
||||||
except requests.exceptions.Timeout:
|
except (requests.exceptions.ConnectionError,
|
||||||
|
requests.exceptions.Timeout):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ChannelManager:
|
class ChannelManager:
|
||||||
|
@ -154,6 +155,29 @@ class ChannelManager:
|
||||||
return Channel(self._relay_url, self._appid, channelid, self._side,
|
return Channel(self._relay_url, self._appid, channelid, self._side,
|
||||||
self._handle_welcome, self._wait, self._timeout)
|
self._handle_welcome, self._wait, self._timeout)
|
||||||
|
|
||||||
|
def close_on_error(f): # method decorator
|
||||||
|
# Clients report certain errors as "moods", so the server can make a
|
||||||
|
# rough count failed connections (due to mismatched passwords, attacks,
|
||||||
|
# or timeouts). We don't report precondition failures, as those are the
|
||||||
|
# responsibility/fault of the local application code. We count
|
||||||
|
# non-precondition errors in case they represent server-side problems.
|
||||||
|
def _f(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return f(self, *args, **kwargs)
|
||||||
|
except Timeout:
|
||||||
|
self.close(u"lonely")
|
||||||
|
raise
|
||||||
|
except WrongPasswordError:
|
||||||
|
self.close(u"scared")
|
||||||
|
raise
|
||||||
|
except (TypeError, UsageError):
|
||||||
|
# preconditions don't warrant _close_with_error()
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
self.close(u"other-error")
|
||||||
|
raise
|
||||||
|
return _f
|
||||||
|
|
||||||
class Wormhole:
|
class Wormhole:
|
||||||
motd_displayed = False
|
motd_displayed = False
|
||||||
version_warning_displayed = False
|
version_warning_displayed = False
|
||||||
|
@ -238,6 +262,7 @@ class Wormhole:
|
||||||
idSymmetric=to_bytes(self._appid))
|
idSymmetric=to_bytes(self._appid))
|
||||||
self.msg1 = self.sp.start()
|
self.msg1 = self.sp.start()
|
||||||
|
|
||||||
|
@close_on_error
|
||||||
def derive_key(self, purpose, length=SecretBox.KEY_SIZE):
|
def derive_key(self, purpose, length=SecretBox.KEY_SIZE):
|
||||||
if not isinstance(purpose, type(u"")): raise TypeError(type(purpose))
|
if not isinstance(purpose, type(u"")): raise TypeError(type(purpose))
|
||||||
return HKDF(self.key, length, CTXinfo=to_bytes(purpose))
|
return HKDF(self.key, length, CTXinfo=to_bytes(purpose))
|
||||||
|
@ -266,6 +291,7 @@ class Wormhole:
|
||||||
self.key = self.sp.finish(pake_msg)
|
self.key = self.sp.finish(pake_msg)
|
||||||
self.verifier = self.derive_key(u"wormhole:verifier")
|
self.verifier = self.derive_key(u"wormhole:verifier")
|
||||||
|
|
||||||
|
@close_on_error
|
||||||
def get_verifier(self):
|
def get_verifier(self):
|
||||||
if self._closed: raise UsageError
|
if self._closed: raise UsageError
|
||||||
if self.code is None: raise UsageError
|
if self.code is None: raise UsageError
|
||||||
|
@ -273,6 +299,7 @@ class Wormhole:
|
||||||
self._get_key()
|
self._get_key()
|
||||||
return self.verifier
|
return self.verifier
|
||||||
|
|
||||||
|
@close_on_error
|
||||||
def send_data(self, outbound_data, phase=u"data"):
|
def send_data(self, outbound_data, phase=u"data"):
|
||||||
if not isinstance(outbound_data, type(b"")):
|
if not isinstance(outbound_data, type(b"")):
|
||||||
raise TypeError(type(outbound_data))
|
raise TypeError(type(outbound_data))
|
||||||
|
@ -291,6 +318,7 @@ class Wormhole:
|
||||||
outbound_encrypted = self._encrypt_data(data_key, outbound_data)
|
outbound_encrypted = self._encrypt_data(data_key, outbound_data)
|
||||||
self._channel.send(phase, outbound_encrypted)
|
self._channel.send(phase, outbound_encrypted)
|
||||||
|
|
||||||
|
@close_on_error
|
||||||
def get_data(self, phase=u"data"):
|
def get_data(self, phase=u"data"):
|
||||||
if not isinstance(phase, type(u"")): raise TypeError(type(phase))
|
if not isinstance(phase, type(u"")): raise TypeError(type(phase))
|
||||||
if phase in self._got_data: raise UsageError # only call this once
|
if phase in self._got_data: raise UsageError # only call this once
|
||||||
|
@ -308,6 +336,8 @@ class Wormhole:
|
||||||
raise WrongPasswordError
|
raise WrongPasswordError
|
||||||
|
|
||||||
def close(self, mood=None):
|
def close(self, mood=None):
|
||||||
|
if not isinstance(mood, (type(None), type(u""))):
|
||||||
|
raise TypeError(type(mood))
|
||||||
self._closed = True
|
self._closed = True
|
||||||
if self._channel:
|
if self._channel:
|
||||||
c, self._channel = self._channel, None
|
c, self._channel = self._channel, None
|
||||||
|
|
Loading…
Reference in New Issue
Block a user