wormhole/invitation code is now unicode
This commit is contained in:
		
							parent
							
								
									7f6410812c
								
							
						
					
					
						commit
						35768d6738
					
				
							
								
								
									
										11
									
								
								docs/api.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								docs/api.md
									
									
									
									
									
								
							| 
						 | 
					@ -157,8 +157,8 @@ include randomly-selected words or characters. Dice, coin flips, shuffled
 | 
				
			||||||
cards, or repeated sampling of a high-resolution stopwatch are all useful
 | 
					cards, or repeated sampling of a high-resolution stopwatch are all useful
 | 
				
			||||||
techniques.
 | 
					techniques.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note that the code is a human-readable string (the python "str" type: so
 | 
					Note that the code is a human-readable string (the python "unicode" type in
 | 
				
			||||||
unicode in python3, plain bytes in python2).
 | 
					python2, "str" in python3).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Application Identifier
 | 
					## Application Identifier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -248,13 +248,10 @@ python2, "bytes" in python3):
 | 
				
			||||||
* data in/out
 | 
					* data in/out
 | 
				
			||||||
* transit records in/out
 | 
					* transit records in/out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Some human-readable parameters are passed as strings: "str" in python2, "str"
 | 
					Other (human-facing) values are always unicode ("unicode" in python2, "str"
 | 
				
			||||||
(i.e. unicode) in python3:
 | 
					in python3):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* wormhole code
 | 
					* wormhole code
 | 
				
			||||||
 | 
					 | 
				
			||||||
And some are always unicode, in both python2 and python3:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* relay URL
 | 
					* relay URL
 | 
				
			||||||
* transit URLs
 | 
					* transit URLs
 | 
				
			||||||
* transit connection hints (e.g. "host:port")
 | 
					* transit connection hints (e.g. "host:port")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,7 +186,7 @@ class Wormhole:
 | 
				
			||||||
        if self.code is not None: raise UsageError
 | 
					        if self.code is not None: raise UsageError
 | 
				
			||||||
        channelid = self._channel_manager.allocate()
 | 
					        channelid = self._channel_manager.allocate()
 | 
				
			||||||
        code = codes.make_code(channelid, code_length)
 | 
					        code = codes.make_code(channelid, code_length)
 | 
				
			||||||
        assert isinstance(code, str), type(code)
 | 
					        assert isinstance(code, type(u"")), type(code)
 | 
				
			||||||
        self._set_code_and_channelid(code)
 | 
					        self._set_code_and_channelid(code)
 | 
				
			||||||
        self._start()
 | 
					        self._start()
 | 
				
			||||||
        return code
 | 
					        return code
 | 
				
			||||||
| 
						 | 
					@ -198,7 +198,7 @@ class Wormhole:
 | 
				
			||||||
        return code
 | 
					        return code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_code(self, code): # used for human-made pre-generated codes
 | 
					    def set_code(self, code): # used for human-made pre-generated codes
 | 
				
			||||||
        if not isinstance(code, str): raise UsageError
 | 
					        if not isinstance(code, type(u"")): raise UsageError
 | 
				
			||||||
        if self.code is not None: raise UsageError
 | 
					        if self.code is not None: raise UsageError
 | 
				
			||||||
        self._set_code_and_channelid(code)
 | 
					        self._set_code_and_channelid(code)
 | 
				
			||||||
        self._start()
 | 
					        self._start()
 | 
				
			||||||
| 
						 | 
					@ -215,7 +215,7 @@ class Wormhole:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _start(self):
 | 
					    def _start(self):
 | 
				
			||||||
        # allocate the rest now too, so it can be serialized
 | 
					        # allocate the rest now too, so it can be serialized
 | 
				
			||||||
        self.sp = SPAKE2_Symmetric(self.code.encode("ascii"),
 | 
					        self.sp = SPAKE2_Symmetric(to_bytes(self.code),
 | 
				
			||||||
                                   idSymmetric=to_bytes(self._appid))
 | 
					                                   idSymmetric=to_bytes(self._appid))
 | 
				
			||||||
        self.msg1 = self.sp.start()
 | 
					        self.msg1 = self.sp.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ def make_code(channel_id, code_length):
 | 
				
			||||||
            words.append(byte_to_odd_word[os.urandom(1)].lower())
 | 
					            words.append(byte_to_odd_word[os.urandom(1)].lower())
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            words.append(byte_to_even_word[os.urandom(1)].lower())
 | 
					            words.append(byte_to_even_word[os.urandom(1)].lower())
 | 
				
			||||||
    return str(channel_id) + "-" + "-".join(words)
 | 
					    return u"%d-%s" % (channel_id, u"-".join(words))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def extract_channel_id(code):
 | 
					def extract_channel_id(code):
 | 
				
			||||||
    channel_id = int(code.split("-")[0])
 | 
					    channel_id = int(code.split("-")[0])
 | 
				
			||||||
| 
						 | 
					@ -82,7 +82,7 @@ def input_code_with_completion(prompt, get_channel_ids, code_length):
 | 
				
			||||||
    readline.set_completer(c.wrap_completer)
 | 
					    readline.set_completer(c.wrap_completer)
 | 
				
			||||||
    readline.set_completer_delims("")
 | 
					    readline.set_completer_delims("")
 | 
				
			||||||
    code = six.moves.input(prompt)
 | 
					    code = six.moves.input(prompt)
 | 
				
			||||||
    return code
 | 
					    return code.decode("utf-8")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    code = input_code_with_completion("Enter wormhole code: ", lambda: [], 2)
 | 
					    code = input_code_with_completion("Enter wormhole code: ", lambda: [], 2)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ def receive(args):
 | 
				
			||||||
    w = Wormhole(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 = u"0-"
 | 
				
			||||||
    code = args.code
 | 
					    code = args.code
 | 
				
			||||||
    if not code:
 | 
					    if not code:
 | 
				
			||||||
        code = w.input_code("Enter receive wormhole code: ", args.code_length)
 | 
					        code = w.input_code("Enter receive wormhole code: ", args.code_length)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ def send(args):
 | 
				
			||||||
    w = Wormhole(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 = u"0-"
 | 
				
			||||||
    if args.code:
 | 
					    if args.code:
 | 
				
			||||||
        w.set_code(args.code)
 | 
					        w.set_code(args.code)
 | 
				
			||||||
        code = args.code
 | 
					        code = args.code
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,7 +69,8 @@ p = subparsers.add_parser("send",
 | 
				
			||||||
                          usage="wormhole send [FILENAME]")
 | 
					                          usage="wormhole send [FILENAME]")
 | 
				
			||||||
p.add_argument("--text", metavar="MESSAGE",
 | 
					p.add_argument("--text", metavar="MESSAGE",
 | 
				
			||||||
               help="text message to send, instead of a file")
 | 
					               help="text message to send, instead of a file")
 | 
				
			||||||
p.add_argument("--code", metavar="CODE", help="human-generated code phrase")
 | 
					p.add_argument("--code", metavar="CODE", help="human-generated code phrase",
 | 
				
			||||||
 | 
					               type=type(u""))
 | 
				
			||||||
p.add_argument("-0", dest="zeromode", action="store_true",
 | 
					p.add_argument("-0", dest="zeromode", action="store_true",
 | 
				
			||||||
               help="enable no-code anything-goes mode")
 | 
					               help="enable no-code anything-goes mode")
 | 
				
			||||||
p.add_argument("what", nargs="?", default=None, metavar="[FILENAME]",
 | 
					p.add_argument("what", nargs="?", default=None, metavar="[FILENAME]",
 | 
				
			||||||
| 
						 | 
					@ -95,6 +96,7 @@ p.add_argument("code", nargs="?", default=None, metavar="[CODE]",
 | 
				
			||||||
               help=dedent("""\
 | 
					               help=dedent("""\
 | 
				
			||||||
               The magic-wormhole code, from the sender. If omitted, the
 | 
					               The magic-wormhole code, from the sender. If omitted, the
 | 
				
			||||||
               program will ask for it, using tab-completion."""),
 | 
					               program will ask for it, using tab-completion."""),
 | 
				
			||||||
 | 
					               type=type(u""),
 | 
				
			||||||
               )
 | 
					               )
 | 
				
			||||||
p.set_defaults(func=cmd_receive.receive)
 | 
					p.set_defaults(func=cmd_receive.receive)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,8 +140,8 @@ class Blocking(ServerBase, unittest.TestCase):
 | 
				
			||||||
    def test_fixed_code(self):
 | 
					    def test_fixed_code(self):
 | 
				
			||||||
        w1 = BlockingWormhole(APPID, self.relayurl)
 | 
					        w1 = BlockingWormhole(APPID, self.relayurl)
 | 
				
			||||||
        w2 = BlockingWormhole(APPID, self.relayurl)
 | 
					        w2 = BlockingWormhole(APPID, self.relayurl)
 | 
				
			||||||
        w1.set_code("123-purple-elephant")
 | 
					        w1.set_code(u"123-purple-elephant")
 | 
				
			||||||
        w2.set_code("123-purple-elephant")
 | 
					        w2.set_code(u"123-purple-elephant")
 | 
				
			||||||
        d = self.doBoth([w1.send_data, b"data1"], [w2.send_data, b"data2"])
 | 
					        d = self.doBoth([w1.send_data, b"data1"], [w2.send_data, b"data2"])
 | 
				
			||||||
        def _sent(res):
 | 
					        def _sent(res):
 | 
				
			||||||
            return self.doBoth([w1.get_data], [w2.get_data])
 | 
					            return self.doBoth([w1.get_data], [w2.get_data])
 | 
				
			||||||
| 
						 | 
					@ -201,7 +201,7 @@ class Blocking(ServerBase, unittest.TestCase):
 | 
				
			||||||
        self.assertRaises(UsageError, w1.get_verifier)
 | 
					        self.assertRaises(UsageError, w1.get_verifier)
 | 
				
			||||||
        self.assertRaises(UsageError, w1.get_data)
 | 
					        self.assertRaises(UsageError, w1.get_data)
 | 
				
			||||||
        self.assertRaises(UsageError, w1.send_data, b"data")
 | 
					        self.assertRaises(UsageError, w1.send_data, b"data")
 | 
				
			||||||
        w1.set_code("123-purple-elephant")
 | 
					        w1.set_code(u"123-purple-elephant")
 | 
				
			||||||
        self.assertRaises(UsageError, w1.set_code, "123-nope")
 | 
					        self.assertRaises(UsageError, w1.set_code, "123-nope")
 | 
				
			||||||
        self.assertRaises(UsageError, w1.get_code)
 | 
					        self.assertRaises(UsageError, w1.get_code)
 | 
				
			||||||
        w2 = BlockingWormhole(APPID, self.relayurl)
 | 
					        w2 = BlockingWormhole(APPID, self.relayurl)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,7 +82,7 @@ class Scripts(ServerBase, ScriptsBase, unittest.TestCase):
 | 
				
			||||||
    def test_send_text_pre_generated_code(self):
 | 
					    def test_send_text_pre_generated_code(self):
 | 
				
			||||||
        wormhole = self.find_executable()
 | 
					        wormhole = self.find_executable()
 | 
				
			||||||
        server_args = ["--relay-url", self.relayurl]
 | 
					        server_args = ["--relay-url", self.relayurl]
 | 
				
			||||||
        code = "1-abc"
 | 
					        code = u"1-abc"
 | 
				
			||||||
        message = "test message"
 | 
					        message = "test message"
 | 
				
			||||||
        send_args = server_args + [
 | 
					        send_args = server_args + [
 | 
				
			||||||
            "send",
 | 
					            "send",
 | 
				
			||||||
| 
						 | 
					@ -120,7 +120,7 @@ class Scripts(ServerBase, ScriptsBase, unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_send_file_pre_generated_code(self):
 | 
					    def test_send_file_pre_generated_code(self):
 | 
				
			||||||
        self.maxDiff=None
 | 
					        self.maxDiff=None
 | 
				
			||||||
        code = "1-abc"
 | 
					        code = u"1-abc"
 | 
				
			||||||
        filename = "testfile"
 | 
					        filename = "testfile"
 | 
				
			||||||
        message = "test message"
 | 
					        message = "test message"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -128,8 +128,8 @@ class Basic(ServerBase, unittest.TestCase):
 | 
				
			||||||
    def test_fixed_code(self):
 | 
					    def test_fixed_code(self):
 | 
				
			||||||
        w1 = Wormhole(APPID, self.relayurl)
 | 
					        w1 = Wormhole(APPID, self.relayurl)
 | 
				
			||||||
        w2 = Wormhole(APPID, self.relayurl)
 | 
					        w2 = Wormhole(APPID, self.relayurl)
 | 
				
			||||||
        w1.set_code("123-purple-elephant")
 | 
					        w1.set_code(u"123-purple-elephant")
 | 
				
			||||||
        w2.set_code("123-purple-elephant")
 | 
					        w2.set_code(u"123-purple-elephant")
 | 
				
			||||||
        d = self.doBoth(w1.send_data(b"data1"), w2.send_data(b"data2"))
 | 
					        d = self.doBoth(w1.send_data(b"data1"), w2.send_data(b"data2"))
 | 
				
			||||||
        def _sent(res):
 | 
					        def _sent(res):
 | 
				
			||||||
            return self.doBoth(w1.get_data(), w2.get_data())
 | 
					            return self.doBoth(w1.get_data(), w2.get_data())
 | 
				
			||||||
| 
						 | 
					@ -188,7 +188,7 @@ class Basic(ServerBase, unittest.TestCase):
 | 
				
			||||||
        self.assertRaises(UsageError, w1.get_verifier)
 | 
					        self.assertRaises(UsageError, w1.get_verifier)
 | 
				
			||||||
        self.assertRaises(UsageError, w1.send_data, b"data")
 | 
					        self.assertRaises(UsageError, w1.send_data, b"data")
 | 
				
			||||||
        self.assertRaises(UsageError, w1.get_data)
 | 
					        self.assertRaises(UsageError, w1.get_data)
 | 
				
			||||||
        w1.set_code("123-purple-elephant")
 | 
					        w1.set_code(u"123-purple-elephant")
 | 
				
			||||||
        self.assertRaises(UsageError, w1.set_code, "123-nope")
 | 
					        self.assertRaises(UsageError, w1.set_code, "123-nope")
 | 
				
			||||||
        self.assertRaises(UsageError, w1.get_code)
 | 
					        self.assertRaises(UsageError, w1.get_code)
 | 
				
			||||||
        w2 = Wormhole(APPID, self.relayurl)
 | 
					        w2 = Wormhole(APPID, self.relayurl)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,7 +223,7 @@ class Wormhole:
 | 
				
			||||||
        d = self._channel_manager.allocate()
 | 
					        d = self._channel_manager.allocate()
 | 
				
			||||||
        def _got_channelid(channelid):
 | 
					        def _got_channelid(channelid):
 | 
				
			||||||
            code = codes.make_code(channelid, code_length)
 | 
					            code = codes.make_code(channelid, code_length)
 | 
				
			||||||
            assert isinstance(code, str), type(code)
 | 
					            assert isinstance(code, type(u"")), type(code)
 | 
				
			||||||
            self._set_code_and_channelid(code)
 | 
					            self._set_code_and_channelid(code)
 | 
				
			||||||
            self._start()
 | 
					            self._start()
 | 
				
			||||||
            return code
 | 
					            return code
 | 
				
			||||||
| 
						 | 
					@ -231,7 +231,7 @@ class Wormhole:
 | 
				
			||||||
        return d
 | 
					        return d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_code(self, code):
 | 
					    def set_code(self, code):
 | 
				
			||||||
        if not isinstance(code, str): raise UsageError
 | 
					        if not isinstance(code, type(u"")): raise UsageError
 | 
				
			||||||
        if self.code is not None: raise UsageError
 | 
					        if self.code is not None: raise UsageError
 | 
				
			||||||
        self._set_code_and_channelid(code)
 | 
					        self._set_code_and_channelid(code)
 | 
				
			||||||
        self._start()
 | 
					        self._start()
 | 
				
			||||||
| 
						 | 
					@ -248,7 +248,7 @@ class Wormhole:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _start(self):
 | 
					    def _start(self):
 | 
				
			||||||
        # allocate the rest now too, so it can be serialized
 | 
					        # allocate the rest now too, so it can be serialized
 | 
				
			||||||
        self.sp = SPAKE2_Symmetric(self.code.encode("ascii"),
 | 
					        self.sp = SPAKE2_Symmetric(to_bytes(self.code),
 | 
				
			||||||
                                   idSymmetric=to_bytes(self._appid))
 | 
					                                   idSymmetric=to_bytes(self._appid))
 | 
				
			||||||
        self.msg1 = self.sp.start()
 | 
					        self.msg1 = self.sp.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -274,7 +274,7 @@ class Wormhole:
 | 
				
			||||||
        d = json.loads(data)
 | 
					        d = json.loads(data)
 | 
				
			||||||
        self = klass(d["appid"], d["relay_url"])
 | 
					        self = klass(d["appid"], d["relay_url"])
 | 
				
			||||||
        self._set_side(d["side"].encode("ascii"))
 | 
					        self._set_side(d["side"].encode("ascii"))
 | 
				
			||||||
        self._set_code_and_channelid(d["code"].encode("ascii"))
 | 
					        self._set_code_and_channelid(d["code"])
 | 
				
			||||||
        self.sp = SPAKE2_Symmetric.from_serialized(json.dumps(d["spake2"]))
 | 
					        self.sp = SPAKE2_Symmetric.from_serialized(json.dumps(d["spake2"]))
 | 
				
			||||||
        self.msg1 = d["msg1"].decode("hex")
 | 
					        self.msg1 = d["msg1"].decode("hex")
 | 
				
			||||||
        return self
 | 
					        return self
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user