replace blocking Initiator/Receiver with just symmetric Wormhole
first pass, seems to work
This commit is contained in:
parent
bc54a0bbca
commit
056cf107fc
|
@ -1,7 +1,7 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import sys, time, re, requests, json, textwrap
|
import os, sys, time, re, requests, json, textwrap
|
||||||
from binascii import hexlify, unhexlify
|
from binascii import hexlify, unhexlify
|
||||||
from spake2 import SPAKE2_A, SPAKE2_B
|
from spake2 import SPAKE2_Symmetric
|
||||||
from nacl.secret import SecretBox
|
from nacl.secret import SecretBox
|
||||||
from nacl.exceptions import CryptoError
|
from nacl.exceptions import CryptoError
|
||||||
from nacl import utils
|
from nacl import utils
|
||||||
|
@ -19,26 +19,20 @@ class Timeout(Exception):
|
||||||
|
|
||||||
class WrongPasswordError(Exception):
|
class WrongPasswordError(Exception):
|
||||||
"""
|
"""
|
||||||
Key confirmation failed.
|
Key confirmation failed. Either you or your correspondent typed the code
|
||||||
|
wrong, or a would-be man-in-the-middle attacker guessed incorrectly. You
|
||||||
|
could try again, giving both your correspondent and the attacker another
|
||||||
|
chance.
|
||||||
"""
|
"""
|
||||||
# or the data blob was corrupted, and that's why decrypt failed
|
# or the data blob was corrupted, and that's why decrypt failed
|
||||||
def explain(self):
|
def explain(self):
|
||||||
return textwrap.dedent(self.__doc__)
|
return textwrap.dedent(self.__doc__)
|
||||||
|
|
||||||
class InitiatorWrongPasswordError(WrongPasswordError):
|
class ReflectionAttack(Exception):
|
||||||
"""
|
"""An attacker (or bug) reflected our outgoing message back to us."""
|
||||||
Key confirmation failed. Either your correspondent typed the code wrong,
|
|
||||||
or a would-be man-in-the-middle attacker guessed incorrectly. You could
|
|
||||||
try again, giving both your correspondent and the attacker another
|
|
||||||
chance.
|
|
||||||
"""
|
|
||||||
|
|
||||||
class ReceiverWrongPasswordError(WrongPasswordError):
|
class UsageError(Exception):
|
||||||
"""
|
"""The programmer did something wrong."""
|
||||||
Key confirmation failed. Either you typed the code wrong, or a would-be
|
|
||||||
man-in-the-middle attacker guessed incorrectly. You could try again,
|
|
||||||
giving both you and the attacker another chance.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# relay URLs are:
|
# relay URLs are:
|
||||||
# GET /list -> {channel-ids: [INT..]}
|
# GET /list -> {channel-ids: [INT..]}
|
||||||
|
@ -49,7 +43,19 @@ class ReceiverWrongPasswordError(WrongPasswordError):
|
||||||
# GET /CHANNEL-ID/SIDE/poll/MSGNUM (eventsource) -> STR, STR, ..
|
# GET /CHANNEL-ID/SIDE/poll/MSGNUM (eventsource) -> STR, STR, ..
|
||||||
# POST /CHANNEL-ID/SIDE/deallocate -> waiting | deleted
|
# POST /CHANNEL-ID/SIDE/deallocate -> waiting | deleted
|
||||||
|
|
||||||
class Common:
|
class Wormhole:
|
||||||
|
def __init__(self, appid, relay):
|
||||||
|
self.appid = appid
|
||||||
|
self.relay = relay
|
||||||
|
assert self.relay.endswith("/")
|
||||||
|
self.started = time.time()
|
||||||
|
self.wait = 0.5*SECOND
|
||||||
|
self.timeout = 3*MINUTE
|
||||||
|
self.side = None
|
||||||
|
self.code = None
|
||||||
|
self.key = None
|
||||||
|
self.verifier = None
|
||||||
|
|
||||||
def url(self, verb, msgnum=None):
|
def url(self, verb, msgnum=None):
|
||||||
url = "%s%d/%s/%s" % (self.relay, self.channel_id, self.side, verb)
|
url = "%s%d/%s/%s" % (self.relay, self.channel_id, self.side, verb)
|
||||||
if msgnum is not None:
|
if msgnum is not None:
|
||||||
|
@ -107,7 +113,7 @@ class Common:
|
||||||
f.close()
|
f.close()
|
||||||
return msgs
|
return msgs
|
||||||
|
|
||||||
def _allocate(self):
|
def _allocate_channel(self):
|
||||||
r = requests.post(self.relay + "allocate/%s" % self.side)
|
r = requests.post(self.relay + "allocate/%s" % self.side)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
data = r.json()
|
data = r.json()
|
||||||
|
@ -116,19 +122,93 @@ class Common:
|
||||||
channel_id = data["channel-id"]
|
channel_id = data["channel-id"]
|
||||||
return channel_id
|
return channel_id
|
||||||
|
|
||||||
def _post_pake(self):
|
def derive_key(self, purpose, length=SecretBox.KEY_SIZE):
|
||||||
msg = self.sp.start()
|
assert type(purpose) == type(b"")
|
||||||
post_data = {"message": hexlify(msg).decode("ascii")}
|
return HKDF(self.key, length, CTXinfo=purpose)
|
||||||
r = requests.post(self.url("post", "pake"), data=json.dumps(post_data))
|
|
||||||
|
|
||||||
|
def get_code(self, code_length=2):
|
||||||
|
if self.code is not None: raise UsageError
|
||||||
|
self.side = hexlify(os.urandom(5))
|
||||||
|
channel_id = self._allocate_channel() # allocate channel
|
||||||
|
code = codes.make_code(channel_id, code_length)
|
||||||
|
self._set_code_and_channel_id(code)
|
||||||
|
self._start()
|
||||||
|
return code
|
||||||
|
|
||||||
|
def list_channels(self):
|
||||||
|
r = requests.get(self.relay + "list")
|
||||||
|
r.raise_for_status()
|
||||||
|
channel_ids = r.json()["channel-ids"]
|
||||||
|
return channel_ids
|
||||||
|
|
||||||
|
def input_code(self, prompt="Enter wormhole code: ", code_length=2):
|
||||||
|
code = codes.input_code_with_completion(prompt, self.list_channels,
|
||||||
|
code_length)
|
||||||
|
return code
|
||||||
|
|
||||||
|
def set_code(self, code): # used for human-made pre-generated codes
|
||||||
|
if self.code is not None: raise UsageError
|
||||||
|
if self.side is not None: raise UsageError
|
||||||
|
self._set_code_and_channel_id(code)
|
||||||
|
self.side = hexlify(os.urandom(5))
|
||||||
|
self._start()
|
||||||
|
|
||||||
|
def _set_code_and_channel_id(self, code):
|
||||||
|
if self.code is not None: raise UsageError
|
||||||
|
mo = re.search(r'^(\d+)-', code)
|
||||||
|
if not mo:
|
||||||
|
raise ValueError("code (%s) must start with NN-" % code)
|
||||||
|
self.channel_id = int(mo.group(1))
|
||||||
|
self.code = code
|
||||||
|
|
||||||
|
def _start(self):
|
||||||
|
# allocate the rest now too, so it can be serialized
|
||||||
|
self.sp = SPAKE2_Symmetric(self.code.encode("ascii"),
|
||||||
|
idA=self.appid+":SymmetricA",
|
||||||
|
idB=self.appid+":SymmetricB")
|
||||||
|
self.msg1 = self.sp.start()
|
||||||
|
|
||||||
|
def _get_key(self):
|
||||||
|
if not self.key:
|
||||||
|
post_data = {"message": hexlify(self.msg1).decode("ascii")}
|
||||||
|
r = requests.post(self.url("post", "pake"),
|
||||||
|
data=json.dumps(post_data))
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
other_msgs = r.json()["messages"]
|
other_msgs = r.json()["messages"]
|
||||||
return other_msgs
|
|
||||||
|
|
||||||
def _get_pake(self, other_msgs):
|
|
||||||
msgs = self.get(other_msgs, "poll", "pake")
|
msgs = self.get(other_msgs, "poll", "pake")
|
||||||
pake_msg = unhexlify(msgs[0].encode("ascii"))
|
pake_msg = unhexlify(msgs[0].encode("ascii"))
|
||||||
key = self.sp.finish(pake_msg)
|
self.key = self.sp.finish(pake_msg)
|
||||||
return key
|
self.verifier = self.derive_key(self.appid+b":Verifier")
|
||||||
|
|
||||||
|
def get_verifier(self):
|
||||||
|
self._get_key()
|
||||||
|
return self.verifier
|
||||||
|
|
||||||
|
def get_data(self, outbound_data):
|
||||||
|
assert self.code is not None
|
||||||
|
assert self.channel_id is not None
|
||||||
|
|
||||||
|
self._get_key()
|
||||||
|
# Without predefined roles, we can't derive predictably unique keys
|
||||||
|
# for each side, so we use the same key for both. We use random
|
||||||
|
# nonces to keep the messages distinct, and check for reflection.
|
||||||
|
try:
|
||||||
|
data_key = self.derive_key(b"data-key")
|
||||||
|
|
||||||
|
outbound_encrypted = self._encrypt_data(data_key, outbound_data)
|
||||||
|
other_msgs = self._post_data(outbound_encrypted)
|
||||||
|
|
||||||
|
inbound_encrypted = self._get_data(other_msgs)
|
||||||
|
if inbound_encrypted == outbound_encrypted:
|
||||||
|
raise ReflectionAttack
|
||||||
|
try:
|
||||||
|
inbound_data = self._decrypt_data(data_key, inbound_encrypted)
|
||||||
|
except CryptoError:
|
||||||
|
raise WrongPasswordError
|
||||||
|
finally:
|
||||||
|
self._deallocate()
|
||||||
|
return inbound_data
|
||||||
|
|
||||||
def _encrypt_data(self, key, data):
|
def _encrypt_data(self, key, data):
|
||||||
assert len(key) == SecretBox.KEY_SIZE
|
assert len(key) == SecretBox.KEY_SIZE
|
||||||
|
@ -136,6 +216,12 @@ class Common:
|
||||||
nonce = utils.random(SecretBox.NONCE_SIZE)
|
nonce = utils.random(SecretBox.NONCE_SIZE)
|
||||||
return box.encrypt(data, nonce)
|
return box.encrypt(data, nonce)
|
||||||
|
|
||||||
|
def _decrypt_data(self, key, encrypted):
|
||||||
|
assert len(key) == SecretBox.KEY_SIZE
|
||||||
|
box = SecretBox(key)
|
||||||
|
data = box.decrypt(encrypted)
|
||||||
|
return data
|
||||||
|
|
||||||
def _post_data(self, data):
|
def _post_data(self, data):
|
||||||
post_data = json.dumps({"message": hexlify(data).decode("ascii")})
|
post_data = json.dumps({"message": hexlify(data).decode("ascii")})
|
||||||
r = requests.post(self.url("post", "data"), data=post_data)
|
r = requests.post(self.url("post", "data"), data=post_data)
|
||||||
|
@ -148,140 +234,6 @@ class Common:
|
||||||
data = unhexlify(msgs[0].encode("ascii"))
|
data = unhexlify(msgs[0].encode("ascii"))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _decrypt_data(self, key, encrypted):
|
|
||||||
assert len(key) == SecretBox.KEY_SIZE
|
|
||||||
box = SecretBox(key)
|
|
||||||
data = box.decrypt(encrypted)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def _deallocate(self):
|
def _deallocate(self):
|
||||||
r = requests.post(self.url("deallocate"))
|
r = requests.post(self.url("deallocate"))
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
|
||||||
def derive_key(self, purpose, length=SecretBox.KEY_SIZE):
|
|
||||||
assert type(purpose) == type(b"")
|
|
||||||
return HKDF(self.key, length, CTXinfo=purpose)
|
|
||||||
|
|
||||||
class Initiator(Common):
|
|
||||||
def __init__(self, appid, relay):
|
|
||||||
self.appid = appid
|
|
||||||
self.relay = relay
|
|
||||||
assert self.relay.endswith("/")
|
|
||||||
self.started = time.time()
|
|
||||||
self.wait = 0.5*SECOND
|
|
||||||
self.timeout = 3*MINUTE
|
|
||||||
self.side = "initiator"
|
|
||||||
self.key = None
|
|
||||||
self.verifier = None
|
|
||||||
|
|
||||||
def set_code(self, code): # used for human-made pre-generated codes
|
|
||||||
mo = re.search(r'^(\d+)-', code)
|
|
||||||
if not mo:
|
|
||||||
raise ValueError("code (%s) must start with NN-" % code)
|
|
||||||
self.channel_id = int(mo.group(1))
|
|
||||||
self.code = code
|
|
||||||
self.sp = SPAKE2_A(self.code.encode("ascii"),
|
|
||||||
idA=self.appid+":Initiator",
|
|
||||||
idB=self.appid+":Receiver")
|
|
||||||
self._post_pake()
|
|
||||||
|
|
||||||
def get_code(self, code_length=2):
|
|
||||||
channel_id = self._allocate() # allocate channel
|
|
||||||
code = codes.make_code(channel_id, code_length)
|
|
||||||
self.set_code(code)
|
|
||||||
return code
|
|
||||||
|
|
||||||
def _wait_for_key(self):
|
|
||||||
if not self.key:
|
|
||||||
key = self._get_pake([])
|
|
||||||
self.key = key
|
|
||||||
self.verifier = self.derive_key(self.appid+b":Verifier")
|
|
||||||
|
|
||||||
def get_verifier(self):
|
|
||||||
self._wait_for_key()
|
|
||||||
return self.verifier
|
|
||||||
|
|
||||||
def get_data(self, outbound_data):
|
|
||||||
self._wait_for_key()
|
|
||||||
try:
|
|
||||||
outbound_key = self.derive_key(b"sender")
|
|
||||||
outbound_encrypted = self._encrypt_data(outbound_key, outbound_data)
|
|
||||||
other_msgs = self._post_data(outbound_encrypted)
|
|
||||||
|
|
||||||
inbound_encrypted = self._get_data(other_msgs)
|
|
||||||
inbound_key = self.derive_key(b"receiver")
|
|
||||||
try:
|
|
||||||
inbound_data = self._decrypt_data(inbound_key,
|
|
||||||
inbound_encrypted)
|
|
||||||
except CryptoError:
|
|
||||||
raise InitiatorWrongPasswordError
|
|
||||||
finally:
|
|
||||||
self._deallocate()
|
|
||||||
return inbound_data
|
|
||||||
|
|
||||||
|
|
||||||
class Receiver(Common):
|
|
||||||
def __init__(self, appid, relay):
|
|
||||||
self.appid = appid
|
|
||||||
self.relay = relay
|
|
||||||
assert self.relay.endswith("/")
|
|
||||||
self.started = time.time()
|
|
||||||
self.wait = 0.5*SECOND
|
|
||||||
self.timeout = 3*MINUTE
|
|
||||||
self.side = "receiver"
|
|
||||||
self.code = None
|
|
||||||
self.channel_id = None
|
|
||||||
self.key = None
|
|
||||||
self.verifier = None
|
|
||||||
|
|
||||||
def list_channels(self):
|
|
||||||
r = requests.get(self.relay + "list")
|
|
||||||
r.raise_for_status()
|
|
||||||
channel_ids = r.json()["channel-ids"]
|
|
||||||
return channel_ids
|
|
||||||
|
|
||||||
def input_code(self, prompt="Enter wormhole code: ", code_length=2):
|
|
||||||
code = codes.input_code_with_completion(prompt, self.list_channels,
|
|
||||||
code_length)
|
|
||||||
return code
|
|
||||||
|
|
||||||
def set_code(self, code):
|
|
||||||
assert self.code is None
|
|
||||||
assert self.channel_id is None
|
|
||||||
self.code = code
|
|
||||||
self.channel_id = codes.extract_channel_id(code)
|
|
||||||
self.sp = SPAKE2_B(code.encode("ascii"),
|
|
||||||
idA=self.appid+":Initiator",
|
|
||||||
idB=self.appid+":Receiver")
|
|
||||||
|
|
||||||
def _wait_for_key(self):
|
|
||||||
if not self.key:
|
|
||||||
other_msgs = self._post_pake()
|
|
||||||
key = self._get_pake(other_msgs)
|
|
||||||
self.key = key
|
|
||||||
self.verifier = self.derive_key(self.appid+b":Verifier")
|
|
||||||
|
|
||||||
def get_verifier(self):
|
|
||||||
self._wait_for_key()
|
|
||||||
return self.verifier
|
|
||||||
|
|
||||||
def get_data(self, outbound_data):
|
|
||||||
assert self.code is not None
|
|
||||||
assert self.channel_id is not None
|
|
||||||
self._wait_for_key()
|
|
||||||
|
|
||||||
try:
|
|
||||||
outbound_key = self.derive_key(b"receiver")
|
|
||||||
outbound_encrypted = self._encrypt_data(outbound_key, outbound_data)
|
|
||||||
other_msgs = self._post_data(outbound_encrypted)
|
|
||||||
|
|
||||||
inbound_encrypted = self._get_data(other_msgs)
|
|
||||||
inbound_key = self.derive_key(b"sender")
|
|
||||||
try:
|
|
||||||
inbound_data = self._decrypt_data(inbound_key,
|
|
||||||
inbound_encrypted)
|
|
||||||
except CryptoError:
|
|
||||||
raise ReceiverWrongPasswordError
|
|
||||||
finally:
|
|
||||||
self._deallocate()
|
|
||||||
return inbound_data
|
|
||||||
|
|
|
@ -7,24 +7,24 @@ APPID = "lothar.com/wormhole/file-xfer"
|
||||||
@handle_server_error
|
@handle_server_error
|
||||||
def receive_file(args):
|
def receive_file(args):
|
||||||
# we're receiving
|
# we're receiving
|
||||||
from ..blocking.transcribe import Receiver, WrongPasswordError
|
from ..blocking.transcribe import Wormhole, WrongPasswordError
|
||||||
from ..blocking.transit import TransitReceiver, TransitError
|
from ..blocking.transit import TransitReceiver, TransitError
|
||||||
from .progress import start_progress, update_progress, finish_progress
|
from .progress import start_progress, update_progress, finish_progress
|
||||||
|
|
||||||
transit_receiver = TransitReceiver(args.transit_helper)
|
transit_receiver = TransitReceiver(args.transit_helper)
|
||||||
|
|
||||||
r = Receiver(APPID, args.relay_url)
|
w = Wormhole(APPID, args.relay_url)
|
||||||
if args.zeromode:
|
if args.zeromode:
|
||||||
assert not args.code
|
assert not args.code
|
||||||
args.code = "0-"
|
args.code = "0-"
|
||||||
code = args.code
|
code = args.code
|
||||||
if not code:
|
if not code:
|
||||||
code = r.input_code("Enter receive-file wormhole code: ",
|
code = w.input_code("Enter receive-file wormhole code: ",
|
||||||
args.code_length)
|
args.code_length)
|
||||||
r.set_code(code)
|
w.set_code(code)
|
||||||
|
|
||||||
if args.verify:
|
if args.verify:
|
||||||
verifier = binascii.hexlify(r.get_verifier())
|
verifier = binascii.hexlify(w.get_verifier())
|
||||||
print("Verifier %s." % verifier)
|
print("Verifier %s." % verifier)
|
||||||
|
|
||||||
mydata = json.dumps({
|
mydata = json.dumps({
|
||||||
|
@ -34,7 +34,7 @@ def receive_file(args):
|
||||||
},
|
},
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
try:
|
try:
|
||||||
data = json.loads(r.get_data(mydata).decode("utf-8"))
|
data = json.loads(w.get_data(mydata).decode("utf-8"))
|
||||||
except WrongPasswordError as e:
|
except WrongPasswordError as e:
|
||||||
print("ERROR: " + e.explain(), file=sys.stderr)
|
print("ERROR: " + e.explain(), file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
@ -50,7 +50,7 @@ def receive_file(args):
|
||||||
|
|
||||||
# now receive the rest of the owl
|
# now receive the rest of the owl
|
||||||
tdata = data["transit"]
|
tdata = data["transit"]
|
||||||
transit_key = r.derive_key(APPID+"/transit-key")
|
transit_key = w.derive_key(APPID+"/transit-key")
|
||||||
transit_receiver.set_transit_key(transit_key)
|
transit_receiver.set_transit_key(transit_key)
|
||||||
transit_receiver.add_their_direct_hints(tdata["direct_connection_hints"])
|
transit_receiver.add_their_direct_hints(tdata["direct_connection_hints"])
|
||||||
transit_receiver.add_their_relay_hints(tdata["relay_connection_hints"])
|
transit_receiver.add_their_relay_hints(tdata["relay_connection_hints"])
|
||||||
|
|
|
@ -7,25 +7,25 @@ APPID = "lothar.com/wormhole/text-xfer"
|
||||||
@handle_server_error
|
@handle_server_error
|
||||||
def receive_text(args):
|
def receive_text(args):
|
||||||
# we're receiving
|
# we're receiving
|
||||||
from ..blocking.transcribe import Receiver, WrongPasswordError
|
from ..blocking.transcribe import Wormhole, WrongPasswordError
|
||||||
|
|
||||||
r = Receiver(APPID, args.relay_url)
|
w = Wormhole(APPID, args.relay_url)
|
||||||
if args.zeromode:
|
if args.zeromode:
|
||||||
assert not args.code
|
assert not args.code
|
||||||
args.code = "0-"
|
args.code = "0-"
|
||||||
code = args.code
|
code = args.code
|
||||||
if not code:
|
if not code:
|
||||||
code = r.input_code("Enter receive-text wormhole code: ",
|
code = w.input_code("Enter receive-text wormhole code: ",
|
||||||
args.code_length)
|
args.code_length)
|
||||||
r.set_code(code)
|
w.set_code(code)
|
||||||
|
|
||||||
if args.verify:
|
if args.verify:
|
||||||
verifier = binascii.hexlify(r.get_verifier())
|
verifier = binascii.hexlify(w.get_verifier())
|
||||||
print("Verifier %s." % verifier)
|
print("Verifier %s." % verifier)
|
||||||
|
|
||||||
data = json.dumps({"message": "ok"}).encode("utf-8")
|
data = json.dumps({"message": "ok"}).encode("utf-8")
|
||||||
try:
|
try:
|
||||||
them_bytes = r.get_data(data)
|
them_bytes = w.get_data(data)
|
||||||
except WrongPasswordError as e:
|
except WrongPasswordError as e:
|
||||||
print("ERROR: " + e.explain(), file=sys.stderr)
|
print("ERROR: " + e.explain(), file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -7,7 +7,7 @@ APPID = "lothar.com/wormhole/file-xfer"
|
||||||
@handle_server_error
|
@handle_server_error
|
||||||
def send_file(args):
|
def send_file(args):
|
||||||
# we're sending
|
# we're sending
|
||||||
from ..blocking.transcribe import Initiator, WrongPasswordError
|
from ..blocking.transcribe import Wormhole, WrongPasswordError
|
||||||
from ..blocking.transit import TransitSender
|
from ..blocking.transit import TransitSender
|
||||||
from .progress import start_progress, update_progress, finish_progress
|
from .progress import start_progress, update_progress, finish_progress
|
||||||
|
|
||||||
|
@ -15,15 +15,15 @@ def send_file(args):
|
||||||
assert os.path.isfile(filename)
|
assert os.path.isfile(filename)
|
||||||
transit_sender = TransitSender(args.transit_helper)
|
transit_sender = TransitSender(args.transit_helper)
|
||||||
|
|
||||||
i = Initiator(APPID, args.relay_url)
|
w = Wormhole(APPID, args.relay_url)
|
||||||
if args.zeromode:
|
if args.zeromode:
|
||||||
assert not args.code
|
assert not args.code
|
||||||
args.code = "0-"
|
args.code = "0-"
|
||||||
if args.code:
|
if args.code:
|
||||||
i.set_code(args.code)
|
w.set_code(args.code)
|
||||||
code = args.code
|
code = args.code
|
||||||
else:
|
else:
|
||||||
code = i.get_code(args.code_length)
|
code = w.get_code(args.code_length)
|
||||||
other_cmd = "wormhole receive-file"
|
other_cmd = "wormhole receive-file"
|
||||||
if args.verify:
|
if args.verify:
|
||||||
other_cmd = "wormhole --verify receive-file"
|
other_cmd = "wormhole --verify receive-file"
|
||||||
|
@ -35,7 +35,7 @@ def send_file(args):
|
||||||
print()
|
print()
|
||||||
|
|
||||||
if args.verify:
|
if args.verify:
|
||||||
verifier = binascii.hexlify(i.get_verifier())
|
verifier = binascii.hexlify(w.get_verifier())
|
||||||
while True:
|
while True:
|
||||||
ok = raw_input("Verifier %s. ok? (yes/no): " % verifier)
|
ok = raw_input("Verifier %s. ok? (yes/no): " % verifier)
|
||||||
if ok.lower() == "yes":
|
if ok.lower() == "yes":
|
||||||
|
@ -45,7 +45,7 @@ def send_file(args):
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
reject_data = json.dumps({"error": "verification rejected",
|
reject_data = json.dumps({"error": "verification rejected",
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
i.get_data(reject_data)
|
w.get_data(reject_data)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
filesize = os.stat(filename).st_size
|
filesize = os.stat(filename).st_size
|
||||||
|
@ -61,7 +61,7 @@ def send_file(args):
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
them_bytes = i.get_data(data)
|
them_bytes = w.get_data(data)
|
||||||
except WrongPasswordError as e:
|
except WrongPasswordError as e:
|
||||||
print("ERROR: " + e.explain(), file=sys.stderr)
|
print("ERROR: " + e.explain(), file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
@ -70,7 +70,7 @@ def send_file(args):
|
||||||
|
|
||||||
|
|
||||||
tdata = them_d["transit"]
|
tdata = them_d["transit"]
|
||||||
transit_key = i.derive_key(APPID+"/transit-key")
|
transit_key = w.derive_key(APPID+"/transit-key")
|
||||||
transit_sender.set_transit_key(transit_key)
|
transit_sender.set_transit_key(transit_key)
|
||||||
transit_sender.add_their_direct_hints(tdata["direct_connection_hints"])
|
transit_sender.add_their_direct_hints(tdata["direct_connection_hints"])
|
||||||
transit_sender.add_their_relay_hints(tdata["relay_connection_hints"])
|
transit_sender.add_their_relay_hints(tdata["relay_connection_hints"])
|
||||||
|
|
|
@ -7,17 +7,17 @@ APPID = "lothar.com/wormhole/text-xfer"
|
||||||
@handle_server_error
|
@handle_server_error
|
||||||
def send_text(args):
|
def send_text(args):
|
||||||
# we're sending
|
# we're sending
|
||||||
from ..blocking.transcribe import Initiator, WrongPasswordError
|
from ..blocking.transcribe import Wormhole, WrongPasswordError
|
||||||
|
|
||||||
i = Initiator(APPID, args.relay_url)
|
w = Wormhole(APPID, args.relay_url)
|
||||||
if args.zeromode:
|
if args.zeromode:
|
||||||
assert not args.code
|
assert not args.code
|
||||||
args.code = "0-"
|
args.code = "0-"
|
||||||
if args.code:
|
if args.code:
|
||||||
i.set_code(args.code)
|
w.set_code(args.code)
|
||||||
code = args.code
|
code = args.code
|
||||||
else:
|
else:
|
||||||
code = i.get_code(args.code_length)
|
code = w.get_code(args.code_length)
|
||||||
other_cmd = "wormhole receive-text"
|
other_cmd = "wormhole receive-text"
|
||||||
if args.verify:
|
if args.verify:
|
||||||
other_cmd = "wormhole --verify receive-text"
|
other_cmd = "wormhole --verify receive-text"
|
||||||
|
@ -29,7 +29,7 @@ def send_text(args):
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
if args.verify:
|
if args.verify:
|
||||||
verifier = binascii.hexlify(i.get_verifier())
|
verifier = binascii.hexlify(w.get_verifier())
|
||||||
while True:
|
while True:
|
||||||
ok = raw_input("Verifier %s. ok? (yes/no): " % verifier)
|
ok = raw_input("Verifier %s. ok? (yes/no): " % verifier)
|
||||||
if ok.lower() == "yes":
|
if ok.lower() == "yes":
|
||||||
|
@ -39,14 +39,14 @@ def send_text(args):
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
reject_data = json.dumps({"error": "verification rejected",
|
reject_data = json.dumps({"error": "verification rejected",
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
i.get_data(reject_data)
|
w.get_data(reject_data)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
message = args.text
|
message = args.text
|
||||||
data = json.dumps({"message": message,
|
data = json.dumps({"message": message,
|
||||||
}).encode("utf-8")
|
}).encode("utf-8")
|
||||||
try:
|
try:
|
||||||
them_bytes = i.get_data(data)
|
them_bytes = w.get_data(data)
|
||||||
except WrongPasswordError as e:
|
except WrongPasswordError as e:
|
||||||
print("ERROR: " + e.explain(), file=sys.stderr)
|
print("ERROR: " + e.explain(), file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
Loading…
Reference in New Issue
Block a user