Merge lp:~cmiller/desktopcouch/pair-with-oauth into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Chad Miller
Approved revision: 63
Merged at revision: not available
Proposed branch: lp:~cmiller/desktopcouch/pair-with-oauth
Merge into: lp:desktopcouch
Diff against target: None lines
To merge this branch: bzr merge lp:~cmiller/desktopcouch/pair-with-oauth
Reviewer Review Type Date Requested Status
Stuart Langridge (community) Approve
Vincenzo Di Somma (community) Approve
Review via email: mp+11576@code.launchpad.net

Commit message

Assume the couchdb is secure. Big change, that.

Finally, remove pairings when asked to.

Transmit hostid and oauth information to paired devices.

To post a comment you must log in.
Revision history for this message
Stuart Langridge (sil) wrote :

Starting up the pairing tool and then clicking "Listen for invitations" throws the following traceback;

Traceback (most recent call last):
  File "bin/desktopcouch-pair", line 606, in listen
    listening = Listening(couchdb_instance)
  File "bin/desktopcouch-pair", line 398, in __init__
    hostid, userid, listen_port = self.make_listener(couchdb_instance)
  File "bin/desktopcouch-pair", line 335, in make_listener
    couchdb_io.get_my_host_unique_id(create=True),
TypeError: get_my_host_unique_id() takes no arguments (1 given)

review: Needs Fixing
Revision history for this message
Chad Miller (cmiller) wrote :

> Starting up the pairing tool and then clicking "Listen for invitations" throws
> the following traceback;
>
> Traceback (most recent call last):
> File "bin/desktopcouch-pair", line 606, in listen
> listening = Listening(couchdb_instance)
> File "bin/desktopcouch-pair", line 398, in __init__
> hostid, userid, listen_port = self.make_listener(couchdb_instance)
> File "bin/desktopcouch-pair", line 335, in make_listener
> couchdb_io.get_my_host_unique_id(create=True),
> TypeError: get_my_host_unique_id() takes no arguments (1 given)

yeah, this relies on other code ("replicate-to-u1") landing first.

Revision history for this message
Vincenzo Di Somma (vds) wrote :

What ln 228 of the diff means? In any case I'm not a gtk expert but the code looks good and all the tests pass.

review: Approve
58. By Chad Miller

Merge from trunk.

59. By Chad Miller

Do not use the host id as the record id for couchdb, as there may be "deleted"
records with this id.

Make URI parameter optional in get_my_host_unique_id() .

60. By Chad Miller

Finish work on making pairing us oauth.

Rearrange the main widgets so they make more sense.

Revision history for this message
Stuart Langridge (sil) wrote :

Pulled and re-tested. Looks OK. Doesn't show existing paired local servers (should it? or is that in another branch?)

Revision history for this message
Chad Miller (cmiller) wrote :

> What ln 228 of the diff means? In any case I'm not a gtk expert but the code
> looks good and all the tests pass.

If you mean 'Narriative 'Alice'", it refers to a large comment near the top that describes the two roles that the single program plays.

61. By Chad Miller

Use the records API to get the server but do it left-handed, by getting a
database and then accessising the db object's private _server member.

Fix failing tests: Import the file that mutates the environment so that a
separate couchdb server is used for testing. Update put_dynamic_paired_host()
test to take its new hostname parameter.

62. By Chad Miller

Add a column for hostname in listening section, so a populated already-
paired section doesn't look so weird.

Add tests for unpairing.

Combine views of pairings.

Revision history for this message
Stuart Langridge (sil) wrote :

> Pulled and re-tested. Looks OK. Doesn't show existing paired local servers
> (should it? or is that in another branch?)

I am now ecstatically happy, yes I am.

review: Approve
63. By Chad Miller

Save a create-time value in pairing records, so we have something
useful to give to the user. Put this time in the second column of
the already-paired list.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/desktopcouch-pair'
--- bin/desktopcouch-pair 2009-09-04 14:44:20 +0000
+++ bin/desktopcouch-pair 2009-09-11 03:23:30 +0000
@@ -64,9 +64,11 @@
64import gobject64import gobject
65import pango65import pango
6666
67from desktopcouch.pair.couchdb_pairing import couchdb_io
67from desktopcouch.pair.couchdb_pairing import network_io68from desktopcouch.pair.couchdb_pairing import network_io
68from desktopcouch.pair.couchdb_pairing import dbus_io69from desktopcouch.pair.couchdb_pairing import dbus_io
69from desktopcouch.pair import pairing_record_type70from desktopcouch.pair import pairing_record_type
71from desktopcouch import local_files
7072
71discovery_tool_version = "1"73discovery_tool_version = "1"
7274
@@ -133,9 +135,9 @@
133 """The window is destroyed."""135 """The window is destroyed."""
134 self.inviter.close()136 self.inviter.close()
135137
136 def auth_completed(self, remote_host, remote_port, remote_info):138 def auth_completed(self, remote_host, remote_id, remote_oauth):
137 """The auth stage is finished. Now pair with the remote host."""139 """The auth stage is finished. Now pair with the remote host."""
138 pair_with_host(remote_host, remote_port, remote_info)140 pair_with_host(remote_host, remote_id, remote_oauth)
139 self.window.destroy()141 self.window.destroy()
140142
141 def on_close(self):143 def on_close(self):
@@ -162,7 +164,7 @@
162164
163 self.inviter = network_io.start_send_invitation(hostname, port, 165 self.inviter = network_io.start_send_invitation(hostname, port,
164 self.auth_completed, self.secret_message, self.public_seed,166 self.auth_completed, self.secret_message, self.public_seed,
165 self.on_close)167 self.on_close, local_hostid, local_oauth)
166168
167 top_vbox = gtk.VBox()169 top_vbox = gtk.VBox()
168 self.window.add(top_vbox)170 self.window.add(top_vbox)
@@ -210,7 +212,8 @@
210 # FIXME this is unimplemented and unused.212 # FIXME this is unimplemented and unused.
211 self.destroy()213 self.destroy()
212214
213 def __init__(self, remote_host, is_secret_valid, send_valid_key):215 def __init__(self, remote_host, is_secret_valid, send_valid_key,
216 remote_hostid, remote_oauth):
214 self.logging = logging.getLogger(self.__class__.__name__)217 self.logging = logging.getLogger(self.__class__.__name__)
215218
216 self.is_secret_valid = is_secret_valid219 self.is_secret_valid = is_secret_valid
@@ -231,6 +234,8 @@
231 self.window.add(top_vbox)234 self.window.add(top_vbox)
232235
233 self.remote_hostname = dbus_io.get_remote_hostname(remote_host)236 self.remote_hostname = dbus_io.get_remote_hostname(remote_host)
237 self.remote_hostid = remote_hostid
238 self.remote_oauth = remote_oauth
234239
235 description = gtk.Label(240 description = gtk.Label(
236 _("To verify your pairing with %s, enter its secret.") %241 _("To verify your pairing with %s, enter its secret.") %
@@ -279,7 +284,7 @@
279284
280 proposed_secret = unmap_easily_mistaken(self.entry_box.get_text())285 proposed_secret = unmap_easily_mistaken(self.entry_box.get_text())
281 if self.is_secret_valid(proposed_secret):286 if self.is_secret_valid(proposed_secret):
282 pair_with_host(self.remote_hostname, "(port)", "(info)")287 pair_with_host(self.remote_hostname, remote_hostid, remote_oauth)
283 self.send_valid_key(proposed_secret)288 self.send_valid_key(proposed_secret)
284 self.window.destroy()289 self.window.destroy()
285 else:290 else:
@@ -306,13 +311,13 @@
306 self.listener.close()311 self.listener.close()
307312
308 def receive_invitation_challenge(self, remote_address, is_secret_valid,313 def receive_invitation_challenge(self, remote_address, is_secret_valid,
309 send_secret):314 send_secret, remote_hostid, remote_oauth):
310 """When we receive an invitation, check its validity and if315 """When we receive an invitation, check its validity and if
311 it's what we expected, then continue and accept it."""316 it's what we expected, then continue and accept it."""
312317
313 self.logging.warn("received invitation from %s", remote_address)318 self.logging.warn("received invitation from %s", remote_address)
314 self.acceptor = AcceptInvitation(remote_address, is_secret_valid,319 self.acceptor = AcceptInvitation(remote_address, is_secret_valid,
315 send_secret)320 send_secret, remote_hostid, remote_oauth)
316 self.acceptor.window.connect("destroy",321 self.acceptor.window.connect("destroy",
317 lambda *args: setattr(self, "acceptor", None) and False)322 lambda *args: setattr(self, "acceptor", None) and False)
318323
@@ -326,7 +331,9 @@
326331
327 self.listener = network_io.ListenForInvitations(332 self.listener = network_io.ListenForInvitations(
328 self.receive_invitation_challenge, 333 self.receive_invitation_challenge,
329 lambda: self.window.destroy())334 lambda: self.window.destroy(),
335 couchdb_io.get_my_host_unique_id(create=True),
336 local_files.get_oauth_tokens())
330337
331 listen_port = self.listener.get_local_port()338 listen_port = self.listener.get_local_port()
332339
@@ -522,19 +529,6 @@
522 pair_with_cloud_service(service, hostname, port)529 pair_with_cloud_service(service, hostname, port)
523 return530 return
524531
525
526 self.logging.error("Local pairing is not yet supported. Aborting.")
527 fail_note = gtk.MessageDialog(
528 parent=self.window,
529 flags=gtk.DIALOG_DESTROY_WITH_PARENT,
530 buttons=gtk.BUTTONS_OK,
531 type=gtk.MESSAGE_ERROR,
532 message_format =_("Sorry, couchdb authentication is not yet enabled, so local pairing is not supported"))
533 fail_note.run()
534 fail_note.destroy()
535 return False
536
537
538 self.logging.info("connecting to %s:%s tcp to invite",532 self.logging.info("connecting to %s:%s tcp to invite",
539 hostname, port)533 hostname, port)
540 if self.inviting != None:534 if self.inviting != None:
@@ -608,19 +602,6 @@
608 # assume local for this user. FIXME602 # assume local for this user. FIXME
609 pass603 pass
610604
611
612 self.logging.error("Local pairing is not yet supported. Aborting.")
613 fail_note = gtk.MessageDialog(
614 parent=self.window,
615 flags=gtk.DIALOG_DESTROY_WITH_PARENT,
616 buttons=gtk.BUTTONS_OK,
617 type=gtk.MESSAGE_ERROR,
618 message_format =_("Sorry, couchdb authentication is not yet enabled, so local pairing is not supported"))
619 fail_note.run()
620 fail_note.destroy()
621 return False
622
623
624 btn.set_sensitive(False)605 btn.set_sensitive(False)
625 listening = Listening(couchdb_instance)606 listening = Listening(couchdb_instance)
626 listening.window.connect("destroy",607 listening.window.connect("destroy",
@@ -682,14 +663,12 @@
682 self.window.show()663 self.window.show()
683664
684665
685def pair_with_host(host, port, info):666def pair_with_host(hostname, hostid, oauth_data):
686 """We've verified all is correct and authorized, so now we pair667 """We've verified all is correct and authorized, so now we pair
687 the databases."""668 the databases."""
688 logging.info("verified host %s/%s/%s. Done!", host, port, info)669 logging.info("verified host %s/%s/%s. Done!", host, hostid, oauth)
689670
690 # Some kind of two-phase commit would be nice here, before we say 671 couchdb.put_dynamic_paired_host(hostname, hostid, oauth_data)
691 # successful.
692 #couchdb_io.replicate_to(...)
693672
694 success_note = gtk.Dialog(title=_("Paired with %(host)s") % locals(), 673 success_note = gtk.Dialog(title=_("Paired with %(host)s") % locals(),
695 parent=pick_or_listen.window,674 parent=pick_or_listen.window,
696675
=== modified file 'desktopcouch/pair/couchdb_pairing/dbus_io.py'
--- desktopcouch/pair/couchdb_pairing/dbus_io.py 2009-08-26 19:04:39 +0000
+++ desktopcouch/pair/couchdb_pairing/dbus_io.py 2009-09-11 03:23:30 +0000
@@ -210,7 +210,7 @@
210210
211211
212def discover_services(add_commport_name_cb, del_commport_name_cb,212def discover_services(add_commport_name_cb, del_commport_name_cb,
213 show_local=False):213 show_local=True):
214 """Start looking for services. Use two callbacks to handle seeing214 """Start looking for services. Use two callbacks to handle seeing
215 new services and seeing services disappear."""215 new services and seeing services disappear."""
216216
217217
=== modified file 'desktopcouch/pair/couchdb_pairing/network_io.py'
--- desktopcouch/pair/couchdb_pairing/network_io.py 2009-07-28 03:43:02 +0000
+++ desktopcouch/pair/couchdb_pairing/network_io.py 2009-09-11 03:23:30 +0000
@@ -35,18 +35,74 @@
35hash = hashlib.sha51235hash = hashlib.sha512
3636
3737
38def dict_to_bytes(d):
39 """Convert a dictionary of string key/values into a string."""
40 parts = list()
41
42 for k, v in d.iteritems():
43 l = len(k)
44 parts.append(chr(l>>8))
45 parts.append(chr(l&255))
46 parts.append(k)
47
48 l = len(v)
49 parts.append(chr(l>>8))
50 parts.append(chr(l&255))
51 parts.append(v)
52
53
54 blob = "".join(parts)
55 l = len(blob)
56 blob_size = list()
57 blob_size.append(chr(l>>24))
58 blob_size.append(chr(l>>16&255))
59 blob_size.append(chr(l>>8&255))
60 blob_size.append(chr(l&255))
61
62 return "CMbydi0" + "".join(blob_size) + blob
63
64
65def bytes_to_dict(b):
66 """Convert a string from C{dict_to_bytes} back into a dictionary."""
67 if b[:7] != "CMbydi0":
68 raise ValueError("magic bytes missing. Invalid string. %r", b[:10])
69 b = b[7:]
70
71 blob_size = 0
72 for c in b[:4]:
73 blob_size = (blob_size << 8) + ord(c)
74
75 blob = b[4:]
76 if blob_size != len(blob):
77 raise ValueError("bytes are corrupt; expected %d, got %d" % (blob_size,
78 len(blob)))
79
80 d = {}
81 blob_cursor = 0
82
83 while blob_cursor < blob_size:
84 k_len = (ord(blob[blob_cursor+0])<<8) + ord(blob[blob_cursor+1])
85 k = blob[blob_cursor+2:blob_cursor+2+k_len]
86 blob_cursor += k_len + 2
87 v_len = (ord(blob[blob_cursor+0])<<8) + ord(blob[blob_cursor+1])
88 v = blob[blob_cursor+2:blob_cursor+2+v_len]
89 blob_cursor += v_len + 2
90 d[k] = v
91 return d
92
93
38class ListenForInvitations():94class ListenForInvitations():
39 """Narrative "Alice".95 """Narrative "Alice".
4096
41 This is the first half of a TCP listening socket. We spawn off97 This is the first half of a TCP listening socket. We spawn off
42 processors when we accept invitation-connections."""98 processors when we accept invitation-connections."""
4399
44 def __init__(self, get_secret_from_user, on_close):100 def __init__(self, get_secret_from_user, on_close, hostid, oauth_data):
45 """Initialize."""101 """Initialize."""
46 self.logging = logging.getLogger(self.__class__.__name__)102 self.logging = logging.getLogger(self.__class__.__name__)
47103
48 self.factory = ProcessAnInvitationFactory(get_secret_from_user,104 self.factory = ProcessAnInvitationFactory(get_secret_from_user,
49 on_close)105 on_close, hostid, oauth_data)
50 self.listening_port = reactor.listenTCP(0, self.factory)106 self.listening_port = reactor.listenTCP(0, self.factory)
51107
52 def get_local_port(self):108 def get_local_port(self):
@@ -84,15 +140,19 @@
84 self.logging.debug("connection lost")140 self.logging.debug("connection lost")
85 basic.LineReceiver.connectionLost(self, reason)141 basic.LineReceiver.connectionLost(self, reason)
86142
87 def lineReceived(self, message):143 def lineReceived(self, rich_message):
88 """Handler for receipt of a message from the Bob end."""144 """Handler for receipt of a message from the Bob end."""
89 h = hash()145 d = bytes_to_dict(rich_message)
90 digest_nybble_count = h.digest_size * 2146
91 self.expected_hash = message[0:digest_nybble_count]147 self.expected_hash = d.pop("secret_message")
92 self.public_seed = message[digest_nybble_count:]148 self.public_seed = d.pop("public_seed")
149 remote_hostid = d.pop("hostid")
150 remote_oauth = d
151
93 self.factory.get_secret_from_user(self.transport.getPeer().host,152 self.factory.get_secret_from_user(self.transport.getPeer().host,
94 self.check_secret_from_user,153 self.check_secret_from_user,
95 self.send_secret_to_remote)154 self.send_secret_to_remote,
155 remote_hostid, remote_oauth)
96 156
97 def send_secret_to_remote(self, secret_message):157 def send_secret_to_remote(self, secret_message):
98 """A callback for the invitation protocol to start a new phase 158 """A callback for the invitation protocol to start a new phase
@@ -101,12 +161,17 @@
101 h = hash()161 h = hash()
102 h.update(self.public_seed)162 h.update(self.public_seed)
103 h.update(secret_message)163 h.update(secret_message)
104 self.sendLine(h.hexdigest())164 all_dict = dict()
165 all_dict.update(self.factory.oauth_info)
166 all_dict["hostid"] = self.factory.hostid
167 all_dict["secret_message"] = h.hexdigest()
168 self.sendLine(dict_to_bytes(all_dict))
105 169
106 def check_secret_from_user(self, secret_message):170 def check_secret_from_user(self, secret_message):
107 """A callback for the invitation protocol to verify the secret171 """A callback for the invitation protocol to verify the secret
108 that the user gives, against the hash we received over the172 that the user gives, against the hash we received over the
109 network."""173 network."""
174
110 h = hash()175 h = hash()
111 h.update(secret_message)176 h.update(secret_message)
112 digest = h.hexdigest()177 digest = h.hexdigest()
@@ -115,7 +180,11 @@
115 h = hash()180 h = hash()
116 h.update(self.public_seed)181 h.update(self.public_seed)
117 h.update(secret_message)182 h.update(secret_message)
118 self.sendLine(h.hexdigest())183 all_dict = dict()
184 all_dict.update(self.factory.oauth_info)
185 all_dict["hostid"] = self.factory.hostid
186 all_dict["secret_message"] = h.hexdigest()
187 self.sendLine(dict_to_bytes(all_dict))
119188
120 self.logging.debug("User knew secret!")189 self.logging.debug("User knew secret!")
121190
@@ -132,10 +201,12 @@
132201
133 protocol = ProcessAnInvitationProtocol202 protocol = ProcessAnInvitationProtocol
134203
135 def __init__(self, get_secret_from_user, on_close):204 def __init__(self, get_secret_from_user, on_close, hostid, oauth_info):
136 self.logging = logging.getLogger(self.__class__.__name__)205 self.logging = logging.getLogger(self.__class__.__name__)
137 self.get_secret_from_user = get_secret_from_user206 self.get_secret_from_user = get_secret_from_user
138 self.on_close = on_close207 self.on_close = on_close
208 self.hostid = hostid
209 self.oauth_info = oauth_info
139210
140211
141class SendInvitationProtocol(basic.LineReceiver):212class SendInvitationProtocol(basic.LineReceiver):
@@ -153,7 +224,11 @@
153224
154 h = hash()225 h = hash()
155 h.update(self.factory.secret_message)226 h.update(self.factory.secret_message)
156 self.sendLine(h.hexdigest() + self.factory.public_seed)227 d = dict(secret_message=h.hexdigest(),
228 public_seed=self.factory.public_seed,
229 hostid=self.factory.local_hostid)
230 d.update(self.factory.local_oauth_info)
231 self.sendLine(dict_to_bytes(d))
157232
158 h = hash()233 h = hash()
159 h.update(self.factory.public_seed)234 h.update(self.factory.public_seed)
@@ -161,15 +236,19 @@
161 self.expected_hash_of_secret = h.hexdigest()236 self.expected_hash_of_secret = h.hexdigest()
162237
163238
164 def lineReceived(self, message):239 def lineReceived(self, rich_message):
165 """Handler for receipt of a message from the Alice end."""240 """Handler for receipt of a message from the Alice end."""
241 d = bytes_to_dict(rich_message)
242 message = d.pop("secret_message")
243
166 if message == self.expected_hash_of_secret:244 if message == self.expected_hash_of_secret:
167 remote_host = self.transport.getPeer().host245 remote_host = self.transport.getPeer().host
168 try:246 try:
169 remote_hostname = get_remote_hostname(remote_host)247 remote_hostname = get_remote_hostname(remote_host)
170 except dbus.exceptions.DBusException:248 except dbus.exceptions.DBusException:
171 remote_hostname = None249 remote_hostname = None
172 self.factory.auth_complete_cb(remote_hostname, "(port)", "(info)")250 remote_hostid = d.pop("hostid")
251 self.factory.auth_complete_cb(remote_hostname, remote_hostid, d)
173 self.transport.loseConnection()252 self.transport.loseConnection()
174 else:253 else:
175 self.logging.warn("Expected %r from invitation.",254 self.logging.warn("Expected %r from invitation.",
@@ -188,12 +267,14 @@
188 protocol = SendInvitationProtocol267 protocol = SendInvitationProtocol
189268
190 def __init__(self, auth_complete_cb, secret_message, public_seed,269 def __init__(self, auth_complete_cb, secret_message, public_seed,
191 on_close):270 on_close, local_hostid, local_oauth_info):
192 self.logging = logging.getLogger(self.__class__.__name__)271 self.logging = logging.getLogger(self.__class__.__name__)
193 self.auth_complete_cb = auth_complete_cb272 self.auth_complete_cb = auth_complete_cb
194 self.secret_message = secret_message273 self.secret_message = secret_message
195 self.public_seed = public_seed274 self.public_seed = public_seed
196 self.on_close = on_close275 self.on_close = on_close
276 self.local_hostid = local_hostid
277 self.local_oauth_info = local_oauth_info
197 self.logging.debug("initialized")278 self.logging.debug("initialized")
198279
199 def close(self):280 def close(self):
@@ -214,12 +295,12 @@
214295
215 296
216def start_send_invitation(host, port, auth_complete_cb, secret_message,297def start_send_invitation(host, port, auth_complete_cb, secret_message,
217 public_seed, on_close):298 public_seed, on_close, local_hostid, local_oauth):
218 """Instantiate the factory to hold configuration data about sending an299 """Instantiate the factory to hold configuration data about sending an
219 invitation and let the reactor add it to its event-handling loop by way of300 invitation and let the reactor add it to its event-handling loop by way of
220 starting a TCP connection."""301 starting a TCP connection."""
221 factory = SendInvitationFactory(auth_complete_cb, secret_message,302 factory = SendInvitationFactory(auth_complete_cb, secret_message,
222 public_seed, on_close)303 public_seed, on_close, local_hostid, local_oauth)
223 reactor.connectTCP(host, port, factory)304 reactor.connectTCP(host, port, factory)
224305
225 return factory306 return factory
226307
=== modified file 'desktopcouch/pair/tests/test_network_io.py'
--- desktopcouch/pair/tests/test_network_io.py 2009-08-22 13:18:00 +0000
+++ desktopcouch/pair/tests/test_network_io.py 2009-09-11 03:23:30 +0000
@@ -26,10 +26,19 @@
26 start_send_invitation, ListenForInvitations)26 start_send_invitation, ListenForInvitations)
27from desktopcouch.pair.couchdb_pairing.dbus_io import get_local_hostname27from desktopcouch.pair.couchdb_pairing.dbus_io import get_local_hostname
2828
29import os
29import unittest30import unittest
3031
31local_hostname = ".".join(get_local_hostname())32local_hostname = ".".join(get_local_hostname())
3233
34a_hostid = "hostid a"
35a_oauth_data = dict(token="atoken", token_secret="atokensecret",
36 consumer="aconsumer", consumer_secret="aconsumersecret")
37
38b_hostid = "hostid b"
39b_oauth_data = dict(token="btoken", token_secret="btokensecret",
40 consumer="bconsumer", consumer_secret="bconsumersecret")
41
3342
34class TestNetworkIO(unittest.TestCase):43class TestNetworkIO(unittest.TestCase):
3544
@@ -43,8 +52,13 @@
4352
44 secret = "sekrit"53 secret = "sekrit"
4554
46 def listener_get_secret_from_user(sender, f, send_secret):55 def listener_get_secret_from_user(sender, f, send_secret, hostid,
56 oauth_info):
47 """Get secret from user. Try several first."""57 """Get secret from user. Try several first."""
58
59 self.assertEquals("hostid b", hostid)
60 self.assertTrue("token" in oauth_info)
61
48 self.assertFalse(f("sek"))62 self.assertFalse(f("sek"))
49 self.assertFalse(f(""))63 self.assertFalse(f(""))
50 self.assertFalse(f(" fs"))64 self.assertFalse(f(" fs"))
@@ -60,15 +74,16 @@
60 def inviter_close_socket():74 def inviter_close_socket():
61 self._inviter_socket_state = "closed"75 self._inviter_socket_state = "closed"
6276
63 def inviter_complete_auth(a, b, c):77 def inviter_complete_auth(hostname, hostid, oauth_info):
78 self.assertEquals("hostid a", hostid)
79 self.assertTrue("token" in oauth_info)
64 self._inviter_auth_completed = True80 self._inviter_auth_completed = True
6581
66 def listener_complete_auth():82 def listener_complete_auth():
67 self._listener_auth_completed = True83 self._listener_auth_completed = True
6884
69
70 self.listener = ListenForInvitations(listener_get_secret_from_user,85 self.listener = ListenForInvitations(listener_get_secret_from_user,
71 listener_close_socket)86 listener_close_socket, a_hostid, a_oauth_data)
72 listener_port = self.listener.get_local_port()87 listener_port = self.listener.get_local_port()
7388
74 def inviter_display_message(*args):89 def inviter_display_message(*args):
@@ -76,7 +91,8 @@
76 logging.info("display message from inviter: %s", args)91 logging.info("display message from inviter: %s", args)
7792
78 self.inviter = start_send_invitation(local_hostname, listener_port,93 self.inviter = start_send_invitation(local_hostname, listener_port,
79 inviter_complete_auth, secret, "seed", inviter_close_socket)94 inviter_complete_auth, secret, "seed", inviter_close_socket,
95 b_hostid, b_oauth_data)
8096
81 def exit_on_success():97 def exit_on_success():
82 if self._listener_auth_completed and self._inviter_auth_completed:98 if self._listener_auth_completed and self._inviter_auth_completed:

Subscribers

People subscribed via source and target branches