summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authorjamiewalch@chromium.org <jamiewalch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-04 06:26:01 +0000
committerjamiewalch@chromium.org <jamiewalch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-04 06:26:01 +0000
commit8835692aa95097e2df4a2ec2b2db4768578b06a0 (patch)
tree3eb40c08525740259ff976b617befdacad442541 /remoting
parentde1bb9caab81d7a80dac9ebe59a5ea2aa56048dd (diff)
downloadchromium_src-8835692aa95097e2df4a2ec2b2db4768578b06a0.zip
chromium_src-8835692aa95097e2df4a2ec2b2db4768578b06a0.tar.gz
chromium_src-8835692aa95097e2df4a2ec2b2db4768578b06a0.tar.bz2
This CL adds the "request pairing" implementation between the web-app and the host. Specifically:
* Adds a pairing registry to the Chromoting host. * Checks the state of the "remember me" checkbox and sends a pairing request if needed. * Adds the plumbing to get that request to host, and to get the response back to the web-app. * Saves the pairing response to local storage, and uses it next time we connect. * Uses Base64 throughout for the secret, since unencoded random strings can't be serialized via PPAPI. Note that pairing is still disabled because we're still missing per-platform Delegate implementations, a UI for revoking pairings, and policy support for disabling the feature. BUG=156182 Review URL: https://chromiumcodereview.appspot.com/16137004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203865 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r--remoting/client/chromoting_client.cc16
-rw-r--r--remoting/client/chromoting_client.h2
-rw-r--r--remoting/client/client_config.h8
-rw-r--r--remoting/client/client_user_interface.h5
-rw-r--r--remoting/client/plugin/chromoting_instance.cc28
-rw-r--r--remoting/client/plugin/chromoting_instance.h3
-rw-r--r--remoting/host/chromoting_host.cc3
-rw-r--r--remoting/host/chromoting_host.h16
-rw-r--r--remoting/host/chromoting_host_unittest.cc3
-rw-r--r--remoting/host/client_session.cc19
-rw-r--r--remoting/host/client_session.h9
-rw-r--r--remoting/host/client_session_unittest.cc3
-rw-r--r--remoting/host/remoting_me2me_host.cc16
-rw-r--r--remoting/protocol/client_stub.h4
-rw-r--r--remoting/protocol/host_stub.h4
-rw-r--r--remoting/protocol/negotiating_authenticator_unittest.cc1
-rw-r--r--remoting/protocol/pairing_registry.cc7
-rw-r--r--remoting/protocol/pairing_registry.h4
-rw-r--r--remoting/webapp/client_plugin.js20
-rw-r--r--remoting/webapp/client_plugin_async.js39
-rw-r--r--remoting/webapp/client_screen.js49
-rw-r--r--remoting/webapp/client_session.js29
-rw-r--r--remoting/webapp/session_connector.js44
23 files changed, 284 insertions, 48 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
index 4411adf..013060c 100644
--- a/remoting/client/chromoting_client.cc
+++ b/remoting/client/chromoting_client.cc
@@ -55,13 +55,12 @@ void ChromotingClient::Start(
scoped_ptr<protocol::TransportFactory> transport_factory) {
DCHECK(task_runner_->BelongsToCurrentThread());
- // TODO(jamiewalch): Add the plumbing required to get the client id and
- // shared secret from the web-app.
- std::string client_id, shared_secret;
scoped_ptr<protocol::Authenticator> authenticator(
new protocol::NegotiatingClientAuthenticator(
- client_id, shared_secret,
- config_.authentication_tag, config_.fetch_secret_callback,
+ config_.client_pairing_id,
+ config_.client_paired_secret,
+ config_.authentication_tag,
+ config_.fetch_secret_callback,
user_interface_->GetTokenFetcher(config_.host_public_key),
config_.authentication_methods));
@@ -123,6 +122,13 @@ void ChromotingClient::SetCapabilities(
IntersectCapabilities(config_.capabilities, host_capabilities_));
}
+void ChromotingClient::SetPairingResponse(
+ const protocol::PairingResponse& pairing_response) {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+
+ user_interface_->SetPairingResponse(pairing_response);
+}
+
void ChromotingClient::InjectClipboardEvent(
const protocol::ClipboardEvent& event) {
DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h
index d46743c..eb044be 100644
--- a/remoting/client/chromoting_client.h
+++ b/remoting/client/chromoting_client.h
@@ -64,6 +64,8 @@ class ChromotingClient : public protocol::ConnectionToHost::HostEventCallback,
// ClientStub implementation.
virtual void SetCapabilities(
const protocol::Capabilities& capabilities) OVERRIDE;
+ virtual void SetPairingResponse(
+ const protocol::PairingResponse& pairing_response) OVERRIDE;
// ClipboardStub implementation for receiving clipboard data from host.
virtual void InjectClipboardEvent(
diff --git a/remoting/client/client_config.h b/remoting/client/client_config.h
index 35f7286..7270abd 100644
--- a/remoting/client/client_config.h
+++ b/remoting/client/client_config.h
@@ -30,6 +30,14 @@ struct ClientConfig {
// The set of all capabilities supported by the webapp.
std::string capabilities;
+
+ // The host-generated id and secret for paired clients. Paired clients
+ // should set both of these in addition to fetch_secret_callback; the
+ // latter is used if the paired connection fails (for example, if the
+ // pairing has been revoked by the host) and the user needs to prompted
+ // to enter their PIN.
+ std::string client_pairing_id;
+ std::string client_paired_secret;
};
} // namespace remoting
diff --git a/remoting/client/client_user_interface.h b/remoting/client/client_user_interface.h
index 59460f1..9779835 100644
--- a/remoting/client/client_user_interface.h
+++ b/remoting/client/client_user_interface.h
@@ -17,6 +17,7 @@ namespace remoting {
namespace protocol {
class ClipboardStub;
class CursorShapeStub;
+class PairingResponse;
} // namespace protocol
// ClientUserInterface is an interface that must be implemented by
@@ -37,6 +38,10 @@ class ClientUserInterface {
// to the application.
virtual void SetCapabilities(const std::string& capabilities) = 0;
+ // Passes a pairing response message to the client.
+ virtual void SetPairingResponse(
+ const protocol::PairingResponse& pairing_response) = 0;
+
// Get the view's ClipboardStub implementation.
virtual protocol::ClipboardStub* GetClipboardStub() = 0;
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index 3d420ba..8b775c1 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -141,7 +141,7 @@ logging::LogMessageHandlerFunction g_logging_old_handler = NULL;
const char ChromotingInstance::kApiFeatures[] =
"highQualityScaling injectKeyEvent sendClipboardItem remapKey trapKey "
"notifyClientDimensions notifyClientResolution pauseVideo pauseAudio "
- "asyncPin thirdPartyAuth";
+ "asyncPin thirdPartyAuth pinlessAuth";
const char ChromotingInstance::kRequestedCapabilities[] = "";
const char ChromotingInstance::kSupportedCapabilities[] = "";
@@ -289,6 +289,8 @@ void ChromotingInstance::HandleMessage(const pp::Var& message) {
LOG(ERROR) << "Invalid connect() data.";
return;
}
+ data->GetString("clientPairingId", &config.client_pairing_id);
+ data->GetString("clientPairedSecret", &config.client_paired_secret);
if (use_async_pin_dialog_) {
config.fetch_secret_callback =
base::Bind(&ChromotingInstance::FetchSecretFromDialog,
@@ -424,6 +426,13 @@ void ChromotingInstance::HandleMessage(const pp::Var& message) {
return;
}
OnThirdPartyTokenFetched(token, shared_secret);
+ } else if (method == "requestPairing") {
+ std::string client_name;
+ if (!data->GetString("clientName", &client_name)) {
+ LOG(ERROR) << "Invalid requestPairing";
+ return;
+ }
+ RequestPairing(client_name);
}
}
@@ -504,6 +513,14 @@ void ChromotingInstance::SetCapabilities(const std::string& capabilities) {
PostChromotingMessage("setCapabilities", data.Pass());
}
+void ChromotingInstance::SetPairingResponse(
+ const protocol::PairingResponse& pairing_response) {
+ scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue());
+ data->SetString("clientId", pairing_response.client_id());
+ data->SetString("sharedSecret", pairing_response.shared_secret());
+ PostChromotingMessage("pairingResponse", data.Pass());
+}
+
void ChromotingInstance::FetchSecretFromDialog(
bool pairing_supported,
const protocol::SecretFetchedCallback& secret_fetched_callback) {
@@ -779,6 +796,15 @@ void ChromotingInstance::OnThirdPartyTokenFetched(
}
}
+void ChromotingInstance::RequestPairing(const std::string& client_name) {
+ if (!IsConnected()) {
+ return;
+ }
+ protocol::PairingRequest pairing_request;
+ pairing_request.set_client_name(client_name);
+ host_connection_->host_stub()->RequestPairing(pairing_request);
+}
+
ChromotingStats* ChromotingInstance::GetStats() {
if (!client_.get())
return NULL;
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index d90f86d..c71576b 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -119,6 +119,8 @@ class ChromotingInstance :
protocol::ErrorCode error) OVERRIDE;
virtual void OnConnectionReady(bool ready) OVERRIDE;
virtual void SetCapabilities(const std::string& capabilities) OVERRIDE;
+ virtual void SetPairingResponse(
+ const protocol::PairingResponse& pairing_response) OVERRIDE;
virtual protocol::ClipboardStub* GetClipboardStub() OVERRIDE;
virtual protocol::CursorShapeStub* GetCursorShapeStub() OVERRIDE;
virtual scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
@@ -195,6 +197,7 @@ class ChromotingInstance :
void OnPinFetched(const std::string& pin);
void OnThirdPartyTokenFetched(const std::string& token,
const std::string& shared_secret);
+ void RequestPairing(const std::string& client_name);
// Helper method to post messages to the webapp.
void PostChromotingMessage(const std::string& method,
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
index d090e05..fe754ed 100644
--- a/remoting/host/chromoting_host.cc
+++ b/remoting/host/chromoting_host.cc
@@ -298,7 +298,8 @@ void ChromotingHost::OnIncomingSession(
ui_task_runner_,
connection.Pass(),
desktop_environment_factory_,
- max_session_duration_);
+ max_session_duration_,
+ pairing_registry_);
clients_.push_back(client);
}
diff --git a/remoting/host/chromoting_host.h b/remoting/host/chromoting_host.h
index d72e99d..a0dc3d0 100644
--- a/remoting/host/chromoting_host.h
+++ b/remoting/host/chromoting_host.h
@@ -19,8 +19,9 @@
#include "remoting/host/host_status_monitor.h"
#include "remoting/host/host_status_observer.h"
#include "remoting/protocol/authenticator.h"
-#include "remoting/protocol/session_manager.h"
#include "remoting/protocol/connection_to_client.h"
+#include "remoting/protocol/pairing_registry.h"
+#include "remoting/protocol/session_manager.h"
#include "third_party/skia/include/core/SkSize.h"
namespace base {
@@ -139,6 +140,16 @@ class ChromotingHost : public base::NonThreadSafe,
return weak_factory_.GetWeakPtr();
}
+ // The host uses a pairing registry to generate and store pairing information
+ // for clients for PIN-less authentication.
+ scoped_refptr<protocol::PairingRegistry> pairing_registry() const {
+ return pairing_registry_;
+ }
+ void set_pairing_registry(
+ scoped_refptr<protocol::PairingRegistry> pairing_registry) {
+ pairing_registry_ = pairing_registry;
+ }
+
private:
friend class ChromotingHostTest;
@@ -190,6 +201,9 @@ class ChromotingHost : public base::NonThreadSafe,
// The maximum duration of any session.
base::TimeDelta max_session_duration_;
+ // The pairing registry for PIN-less authentication.
+ scoped_refptr<protocol::PairingRegistry> pairing_registry_;
+
base::WeakPtrFactory<ChromotingHost> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ChromotingHost);
diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc
index d7fce86..f7b56e2 100644
--- a/remoting/host/chromoting_host_unittest.cc
+++ b/remoting/host/chromoting_host_unittest.cc
@@ -191,7 +191,8 @@ class ChromotingHostTest : public testing::Test {
task_runner_, // UI
connection.Pass(),
desktop_environment_factory_.get(),
- base::TimeDelta()));
+ base::TimeDelta(),
+ NULL));
connection_ptr->set_host_stub(client.get());
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index 2f17ce8..f4b72c7 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -27,6 +27,7 @@
#include "remoting/proto/event.pb.h"
#include "remoting/protocol/client_stub.h"
#include "remoting/protocol/clipboard_thread_proxy.h"
+#include "remoting/protocol/pairing_registry.h"
// Default DPI to assume for old clients that use notifyClientDimensions.
const int kDefaultDPI = 96;
@@ -43,7 +44,8 @@ ClientSession::ClientSession(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_ptr<protocol::ConnectionToClient> connection,
DesktopEnvironmentFactory* desktop_environment_factory,
- const base::TimeDelta& max_duration)
+ const base::TimeDelta& max_duration,
+ scoped_refptr<protocol::PairingRegistry> pairing_registry)
: event_handler_(event_handler),
connection_(connection.Pass()),
client_jid_(connection_->session()->jid()),
@@ -63,7 +65,8 @@ ClientSession::ClientSession(
video_capture_task_runner_(video_capture_task_runner),
video_encode_task_runner_(video_encode_task_runner),
network_task_runner_(network_task_runner),
- ui_task_runner_(ui_task_runner) {
+ ui_task_runner_(ui_task_runner),
+ pairing_registry_(pairing_registry) {
connection_->SetEventHandler(this);
// TODO(sergeyu): Currently ConnectionToClient expects stubs to be
@@ -172,6 +175,18 @@ void ClientSession::SetCapabilities(
IntersectCapabilities(*client_capabilities_, host_capabilities_));
}
+void ClientSession::RequestPairing(
+ const protocol::PairingRequest& pairing_request) {
+ if (pairing_request.has_client_name()) {
+ protocol::PairingRegistry::Pairing pairing =
+ pairing_registry_->CreatePairing(pairing_request.client_name());
+ protocol::PairingResponse pairing_response;
+ pairing_response.set_client_id(pairing.client_id);
+ pairing_response.set_shared_secret(pairing.shared_secret);
+ connection_->client_stub()->SetPairingResponse(pairing_response);
+ }
+}
+
void ClientSession::OnConnectionAuthenticated(
protocol::ConnectionToClient* connection) {
DCHECK(CalledOnValidThread());
diff --git a/remoting/host/client_session.h b/remoting/host/client_session.h
index add2a0a..0c29029 100644
--- a/remoting/host/client_session.h
+++ b/remoting/host/client_session.h
@@ -24,6 +24,7 @@
#include "remoting/protocol/input_event_tracker.h"
#include "remoting/protocol/input_filter.h"
#include "remoting/protocol/input_stub.h"
+#include "remoting/protocol/pairing_registry.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkSize.h"
@@ -95,7 +96,8 @@ class ClientSession
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_ptr<protocol::ConnectionToClient> connection,
DesktopEnvironmentFactory* desktop_environment_factory,
- const base::TimeDelta& max_duration);
+ const base::TimeDelta& max_duration,
+ scoped_refptr<protocol::PairingRegistry> pairing_registry);
virtual ~ClientSession();
// protocol::HostStub interface.
@@ -107,6 +109,8 @@ class ClientSession
const protocol::AudioControl& audio_control) OVERRIDE;
virtual void SetCapabilities(
const protocol::Capabilities& capabilities) OVERRIDE;
+ virtual void RequestPairing(
+ const remoting::protocol::PairingRequest& pairing_request) OVERRIDE;
// protocol::ConnectionToClient::EventHandler interface.
virtual void OnConnectionAuthenticated(
@@ -224,6 +228,9 @@ class ClientSession
// Used to apply client-requested changes in screen resolution.
scoped_ptr<ScreenControls> screen_controls_;
+ // The pairing registry for PIN-less authentication.
+ scoped_refptr<protocol::PairingRegistry> pairing_registry_;
+
DISALLOW_COPY_AND_ASSIGN(ClientSession);
};
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc
index 314c716..4b55caf 100644
--- a/remoting/host/client_session_unittest.cc
+++ b/remoting/host/client_session_unittest.cc
@@ -164,7 +164,8 @@ void ClientSessionTest::SetUp() {
ui_task_runner, // UI thread.
connection.PassAs<protocol::ConnectionToClient>(),
desktop_environment_factory_.get(),
- base::TimeDelta()));
+ base::TimeDelta(),
+ NULL));
}
void ClientSessionTest::TearDown() {
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 1ac47cc..38765df 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -19,7 +19,6 @@
#include "base/single_thread_task_runner.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
-#include "base/string_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
@@ -462,12 +461,19 @@ void HostProcess::CreateAuthenticatorFactory() {
ShutdownHost(kInitializationFailed);
return;
}
+
+ // TODO(jamiewalch): Add a pairing registry here once all the code
+ // is committed.
+ scoped_refptr<remoting::protocol::PairingRegistry> pairing_registry;
+ //scoped_refptr<protocol::PairingRegistry> pairing_registry(
+ // new protocol::PairingRegistry(
+ // scoped_ptr<protocol::PairingRegistry::Delegate>(
+ // new protocol::NotImplementedPairingRegistryDelegate),
+ // protocol::PairingRegistry::PairedClients()));
+
scoped_ptr<protocol::AuthenticatorFactory> factory;
if (token_url_.is_empty() && token_validation_url_.is_empty()) {
- // TODO(jamiewalch): Add a pairing registry here once all the code
- // is committed.
- scoped_refptr<remoting::protocol::PairingRegistry> pairing_registry;
factory = protocol::Me2MeHostAuthenticatorFactory::CreateWithSharedSecret(
local_certificate, key_pair_, host_secret_hash_, pairing_registry);
@@ -495,6 +501,8 @@ void HostProcess::CreateAuthenticatorFactory() {
factory.reset(new PamAuthorizationFactory(factory.Pass()));
#endif
host_->SetAuthenticatorFactory(factory.Pass());
+
+ host_->set_pairing_registry(pairing_registry);
}
// IPC::Listener implementation.
diff --git a/remoting/protocol/client_stub.h b/remoting/protocol/client_stub.h
index 09a83c5..4507ba7 100644
--- a/remoting/protocol/client_stub.h
+++ b/remoting/protocol/client_stub.h
@@ -30,9 +30,7 @@ class ClientStub : public ClipboardStub,
virtual void SetCapabilities(const Capabilities& capabilities) = 0;
// Passes a pairing response message to the client.
- // TODO(jamiewalch): Make this pure virtual once the PIN-less authentication
- // implementation CLs have landed.
- virtual void SetPairingResponse(const PairingResponse& pairing_response) {}
+ virtual void SetPairingResponse(const PairingResponse& pairing_response) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(ClientStub);
diff --git a/remoting/protocol/host_stub.h b/remoting/protocol/host_stub.h
index d7d5475..46d7534 100644
--- a/remoting/protocol/host_stub.h
+++ b/remoting/protocol/host_stub.h
@@ -41,9 +41,7 @@ class HostStub {
virtual void SetCapabilities(const Capabilities& capabilities) = 0;
// Requests pairing between the host and client for PIN-less authentication.
- // TODO(jamiewalch): Make this pure virtual once the PIN-less authentication
- // implementation CLs have landed.
- virtual void RequestPairing(const PairingRequest& pairing_request) {}
+ virtual void RequestPairing(const PairingRequest& pairing_request) = 0;
protected:
virtual ~HostStub() {}
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc
index 9cc2ebc..9b5bb8b 100644
--- a/remoting/protocol/negotiating_authenticator_unittest.cc
+++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -11,6 +11,7 @@
#include "remoting/protocol/negotiating_authenticator_base.h"
#include "remoting/protocol/negotiating_client_authenticator.h"
#include "remoting/protocol/negotiating_host_authenticator.h"
+#include "remoting/protocol/pairing_registry.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
diff --git a/remoting/protocol/pairing_registry.cc b/remoting/protocol/pairing_registry.cc
index 583d84b..54b66b0 100644
--- a/remoting/protocol/pairing_registry.cc
+++ b/remoting/protocol/pairing_registry.cc
@@ -36,7 +36,10 @@ const PairingRegistry::Pairing& PairingRegistry::CreatePairing(
// Create a random shared secret to authenticate this client.
char buffer[kKeySize];
crypto::RandBytes(buffer, arraysize(buffer));
- result.shared_secret = std::string(buffer, buffer+arraysize(buffer));
+ if (!base::Base64Encode(base::StringPiece(buffer, arraysize(buffer)),
+ &result.shared_secret)) {
+ LOG(FATAL) << "Base64Encode failed.";
+ }
// Save the result via the Delegate and return it to the caller.
paired_clients_[result.client_id] = result;
@@ -59,7 +62,7 @@ std::string PairingRegistry::GetSecret(const std::string& client_id) const {
void NotImplementedPairingRegistryDelegate::Save(
const PairingRegistry::PairedClients& paired_clients) {
NOTIMPLEMENTED();
-};
+}
} // namespace protocol
} // namespace remoting
diff --git a/remoting/protocol/pairing_registry.h b/remoting/protocol/pairing_registry.h
index 4889356..f96097b 100644
--- a/remoting/protocol/pairing_registry.h
+++ b/remoting/protocol/pairing_registry.h
@@ -61,10 +61,6 @@ class PairingRegistry : public base::RefCountedThreadSafe<PairingRegistry>,
virtual ~PairingRegistry();
- // Callback for the Delegate::Load method. Invoked when the stored pairings
- // have been loaded.
- void OnLoad(const PairedClients& paired_clients);
-
scoped_ptr<Delegate> delegate_;
PairedClients paired_clients_;
diff --git a/remoting/webapp/client_plugin.js b/remoting/webapp/client_plugin.js
index 2b28336..e98b345 100644
--- a/remoting/webapp/client_plugin.js
+++ b/remoting/webapp/client_plugin.js
@@ -66,7 +66,8 @@ remoting.ClientPlugin.Feature = {
REMAP_KEY: 'remapKey',
SEND_CLIPBOARD_ITEM: 'sendClipboardItem',
THIRD_PARTY_AUTH: 'thirdPartyAuth',
- TRAP_KEY: 'trapKey'
+ TRAP_KEY: 'trapKey',
+ PINLESS_AUTH: 'pinlessAuth'
};
/**
@@ -102,10 +103,15 @@ remoting.ClientPlugin.prototype.onIncomingIq = function(iq) {};
* authentication methods the client should attempt to use.
* @param {string} authenticationTag A host-specific tag to mix into
* authentication hashes.
+ * @param {string} clientPairingId For paired Me2Me connections, the
+ * pairing id for this client, as issued by the host.
+ * @param {string} clientPairedSecret For paired Me2Me connections, the
+ * paired secret for this client, as issued by the host.
*/
remoting.ClientPlugin.prototype.connect = function(
hostJid, hostPublicKey, localJid, sharedSecret,
- authenticationMethods, authenticationTag) {};
+ authenticationMethods, authenticationTag,
+ clientPairingId, clientPairedSecret) {};
/**
* Release all currently pressed keys.
@@ -199,3 +205,13 @@ remoting.ClientPlugin.prototype.useAsyncPinDialog = function() {};
*/
remoting.ClientPlugin.prototype.onThirdPartyTokenFetched =
function(token, sharedSecret) {};
+
+/**
+ * Request pairing with the host for PIN-less authentication.
+ *
+ * @param {string} clientName The human-readable name of the client.
+ * @param {function(string, string):void} onDone, Callback to receive the
+ * client id and shared secret when they are available.
+ */
+remoting.ClientPlugin.prototype.requestPairing = function(
+ clientName, onDone) {};
diff --git a/remoting/webapp/client_plugin_async.js b/remoting/webapp/client_plugin_async.js
index cb64329..8b60f30 100644
--- a/remoting/webapp/client_plugin_async.js
+++ b/remoting/webapp/client_plugin_async.js
@@ -64,7 +64,8 @@ remoting.ClientPluginAsync = function(plugin) {
this.helloReceived_ = false;
/** @type {function(boolean)|null} */
this.onInitializedCallback_ = null;
-
+ /** @type {function(string, string):void} */
+ this.onPairingComplete_ = function(clientId, sharedSecret) {};
/** @type {remoting.ClientSession.PerfStats} */
this.perfStats_ = new remoting.ClientSession.PerfStats();
@@ -298,6 +299,14 @@ remoting.ClientPluginAsync.prototype.handleMessage_ = function(messageStr) {
/** @type {string} */ message.data['hostPublicKey'];
var scope = /** @type {string} */ message.data['scope'];
this.fetchThirdPartyTokenHandler(tokenUrl, hostPublicKey, scope);
+ } else if (message.method == 'pairingResponse') {
+ var clientId = /** @type {string} */ message.data['clientId'];
+ var sharedSecret = /** @type {string} */ message.data['sharedSecret'];
+ if (typeof clientId != 'string' || typeof sharedSecret != 'string') {
+ console.error('Received incorrect pairingResponse message.');
+ return;
+ }
+ this.onPairingComplete_(clientId, sharedSecret);
}
};
@@ -385,10 +394,15 @@ remoting.ClientPluginAsync.prototype.onIncomingIq = function(iq) {
* authentication methods the client should attempt to use.
* @param {string} authenticationTag A host-specific tag to mix into
* authentication hashes.
+ * @param {string} clientPairingId For paired Me2Me connections, the
+ * pairing id for this client, as issued by the host.
+ * @param {string} clientPairedSecret For paired Me2Me connections, the
+ * paired secret for this client, as issued by the host.
*/
remoting.ClientPluginAsync.prototype.connect = function(
hostJid, hostPublicKey, localJid, sharedSecret,
- authenticationMethods, authenticationTag) {
+ authenticationMethods, authenticationTag,
+ clientPairingId, clientPairedSecret) {
this.plugin.postMessage(JSON.stringify(
{ method: 'connect', data: {
hostJid: hostJid,
@@ -397,7 +411,9 @@ remoting.ClientPluginAsync.prototype.connect = function(
sharedSecret: sharedSecret,
authenticationMethods: authenticationMethods,
authenticationTag: authenticationTag,
- capabilities: this.capabilities_.join(" ")
+ capabilities: this.capabilities_.join(" "),
+ clientPairingId: clientPairingId,
+ clientPairedSecret: clientPairedSecret
}
}));
};
@@ -568,6 +584,23 @@ remoting.ClientPluginAsync.prototype.onThirdPartyTokenFetched = function(
};
/**
+ * Request pairing with the host for PIN-less authentication.
+ *
+ * @param {string} clientName The human-readable name of the client.
+ * @param {function(string, string):void} onDone, Callback to receive the
+ * client id and shared secret when they are available.
+ */
+remoting.ClientPluginAsync.prototype.requestPairing =
+ function(clientName, onDone) {
+ if (!this.hasFeature(remoting.ClientPlugin.Feature.PINLESS_AUTH)) {
+ return;
+ }
+ this.onPairingComplete_ = onDone;
+ this.plugin.postMessage(JSON.stringify(
+ { method: 'requestPairing', data: { clientName: clientName } }));
+};
+
+/**
* If we haven't yet received a "hello" message from the plugin, change its
* size so that the user can confirm it if click-to-play is enabled, or can
* see the "this plugin is disabled" message if it is actually disabled.
diff --git a/remoting/webapp/client_screen.js b/remoting/webapp/client_screen.js
index feaf29d..6cc70de 100644
--- a/remoting/webapp/client_screen.js
+++ b/remoting/webapp/client_screen.js
@@ -274,6 +274,10 @@ remoting.connectMe2MeHostVersionAcknowledged_ = function(host) {
var pinForm = document.getElementById('pin-form');
/** @type {Element} */
var pinCancel = document.getElementById('cancel-pin-entry-button');
+ /** @type {Element} */
+ var rememberPin = document.getElementById('remember-pin');
+ /** @type {Element} */
+ var rememberPinCheckbox = document.getElementById('remember-pin-checkbox');
/**
* Event handler for both the 'submit' and 'cancel' actions. Using
* a single handler for both greatly simplifies the task of making
@@ -292,23 +296,38 @@ remoting.connectMe2MeHostVersionAcknowledged_ = function(host) {
event.preventDefault();
remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
onPinFetched(pin);
+ if (/** @type {boolean} */(rememberPinCheckbox.checked)) {
+ remoting.connector.pairingRequested = true;
+ }
} else {
remoting.setMode(remoting.AppMode.HOME);
}
};
pinForm.addEventListener('submit', onSubmitOrCancel, false);
pinCancel.addEventListener('click', onSubmitOrCancel, false);
-
- var rememberPin = document.getElementById('remember-pin');
rememberPin.hidden = !supportsPairing;
- var checkbox = /** @type {HTMLInputElement} */
- document.getElementById('remember-pin-checkbox');
- checkbox.checked = false;
+ rememberPinCheckbox.checked = false;
var message = document.getElementById('pin-message');
l10n.localizeElement(message, host.hostName);
remoting.setMode(remoting.AppMode.CLIENT_PIN_PROMPT);
};
- remoting.connector.connectMe2Me(host, requestPin, fetchThirdPartyToken);
+
+ /** @param {Object} settings */
+ var connectMe2MeHostSettingsRetrieved = function(settings) {
+ /** @type {string} */
+ var clientId = '';
+ /** @type {string} */
+ var sharedSecret = '';
+ var pairingInfo = /** @type {Object} */ (settings['pairingInfo']);
+ if (pairingInfo) {
+ clientId = /** @type {string} */ (pairingInfo['clientId']);
+ sharedSecret = /** @type {string} */ (pairingInfo['sharedSecret']);
+ }
+ remoting.connector.connectMe2Me(host, requestPin, fetchThirdPartyToken,
+ clientId, sharedSecret);
+ }
+
+ remoting.HostSettings.load(host.hostId, connectMe2MeHostSettingsRetrieved);
};
/** @param {remoting.ClientSession} clientSession */
@@ -323,4 +342,22 @@ remoting.onConnected = function(clientSession) {
remoting.toolbar.preview();
remoting.clipboard.startSession();
updateStatistics_();
+ if (remoting.connector.pairingRequested) {
+ /**
+ * @param {string} clientId
+ * @param {string} sharedSecret
+ */
+ var onPairingComplete = function(clientId, sharedSecret) {
+ var pairingInfo = {
+ pairingInfo: {
+ clientId: clientId,
+ sharedSecret: sharedSecret
+ }
+ };
+ remoting.HostSettings.save(clientSession.hostId, pairingInfo);
+ };
+ // TODO(jamiewalch): Since we can't get a descriptive name for the local
+ // computer from Javascript, pass the empty string for now.
+ clientSession.requestPairing('', onPairingComplete);
+ }
};
diff --git a/remoting/webapp/client_session.js b/remoting/webapp/client_session.js
index f40fa85..b81260dc 100644
--- a/remoting/webapp/client_session.js
+++ b/remoting/webapp/client_session.js
@@ -41,12 +41,17 @@ var remoting = remoting || {};
* Mixed into authentication hashes for some authentication methods.
* @param {remoting.ClientSession.Mode} mode The mode of this connection.
* @param {string} hostDisplayName The name of the host for display purposes.
+ * @param {string} clientPairingId For paired Me2Me connections, the
+ * pairing id for this client, as issued by the host.
+ * @param {string} clientPairedSecret For paired Me2Me connections, the
+ * paired secret for this client, as issued by the host.
* @constructor
*/
remoting.ClientSession = function(hostJid, clientJid, hostPublicKey, accessCode,
fetchPin, fetchThirdPartyToken,
authenticationMethods, hostId,
- mode, hostDisplayName) {
+ mode, hostDisplayName,
+ clientPairingId, clientPairedSecret) {
this.state = remoting.ClientSession.State.CREATED;
this.hostJid = hostJid;
@@ -59,11 +64,16 @@ remoting.ClientSession = function(hostJid, clientJid, hostPublicKey, accessCode,
/** @private */
this.fetchThirdPartyToken_ = fetchThirdPartyToken;
this.authenticationMethods = authenticationMethods;
+ /** @type {string} */
this.hostId = hostId;
/** @type {string} */
this.hostDisplayName = hostDisplayName;
/** @type {remoting.ClientSession.Mode} */
this.mode = mode;
+ /** @private */
+ this.clientPairingId_ = clientPairingId;
+ /** @private */
+ this.clientPairedSecret_ = clientPairedSecret
this.sessionId = '';
/** @type {remoting.ClientPlugin} */
this.plugin = null;
@@ -768,8 +778,8 @@ remoting.ClientSession.prototype.connectPluginToWcs_ = function() {
*/
remoting.ClientSession.prototype.connectToHost_ = function(sharedSecret) {
this.plugin.connect(this.hostJid, this.hostPublicKey, this.clientJid,
- sharedSecret, this.authenticationMethods,
- this.hostId);
+ sharedSecret, this.authenticationMethods, this.hostId,
+ this.clientPairingId_, this.clientPairedSecret_);
};
/**
@@ -1058,6 +1068,19 @@ remoting.ClientSession.prototype.logHostOfflineErrors = function(enable) {
};
/**
+ * Request pairing with the host for PIN-less authentication.
+ *
+ * @param {string} clientName The human-readable name of the client.
+ * @param {function(string, string):void} onDone Callback to receive the
+ * client id and shared secret when they are available.
+ */
+remoting.ClientSession.prototype.requestPairing = function(clientName, onDone) {
+ if (this.plugin) {
+ this.plugin.requestPairing(clientName, onDone);
+ }
+};
+
+/**
* Toggles between full-screen and windowed mode.
* @return {void} Nothing.
* @private
diff --git a/remoting/webapp/session_connector.js b/remoting/webapp/session_connector.js
index 779a00f..86eff44 100644
--- a/remoting/webapp/session_connector.js
+++ b/remoting/webapp/session_connector.js
@@ -70,6 +70,14 @@ remoting.SessionConnector = function(pluginParent, onOk, onError) {
*/
remoting.SessionConnector.prototype.reset = function() {
/**
+ * Set to true to indicate that the user requested pairing when entering
+ * their PIN for a Me2Me connection.
+ *
+ * @type {boolean}
+ */
+ this.pairingRequested = false;
+
+ /**
* String used to identify the host to which to connect. For IT2Me, this is
* the first 7 digits of the access code; for Me2Me it is the host identifier.
*
@@ -79,6 +87,23 @@ remoting.SessionConnector.prototype.reset = function() {
this.hostId_ = '';
/**
+ * For paired connections, the client id of this device, issued by the host.
+ *
+ * @type {string}
+ * @private
+ */
+ this.clientPairingId_ = '';
+
+ /**
+ * For paired connections, the paired secret for this device, issued by the
+ * host.
+ *
+ * @type {string}
+ * @private
+ */
+ this.clientPairedSecret_ = '';
+
+ /**
* String used to authenticate to the host on connection. For IT2Me, this is
* the access code; for Me2Me it is the PIN.
*
@@ -153,14 +178,21 @@ remoting.SessionConnector.prototype.reset = function() {
* function(string, string): void): void}
* fetchThirdPartyToken Function to obtain a token from a third party
* authenticaiton server.
+ * @param {string} clientPairingId The client id issued by the host when
+ * this device was paired, if it is already paired.
+ * @param {string} clientPairedSecret The shared secret issued by the host when
+ * this device was paired, if it is already paired.
* @return {void} Nothing.
*/
-remoting.SessionConnector.prototype.connectMe2Me = function(
- host, fetchPin, fetchThirdPartyToken) {
+remoting.SessionConnector.prototype.connectMe2Me =
+ function(host, fetchPin, fetchThirdPartyToken,
+ clientPairingId, clientPairedSecret) {
// Cancel any existing connect operation.
this.cancel();
this.hostId_ = host.hostId;
+ this.clientPairingId_ = clientPairingId;
+ this.clientPairedSecret_ = clientPairedSecret;
this.hostJid_ = host.jabberId;
this.hostPublicKey_ = host.publicKey;
this.fetchPin_ = fetchPin;
@@ -318,7 +350,8 @@ remoting.SessionConnector.prototype.createSessionIfReady_ = function() {
this.clientSession_ = new remoting.ClientSession(
this.hostJid_, this.clientJid_, this.hostPublicKey_, this.passPhrase_,
this.fetchPin_, this.fetchThirdPartyToken_, securityTypes, this.hostId_,
- this.connectionMode_, this.hostDisplayName_);
+ this.connectionMode_, this.hostDisplayName_, this.clientPairingId_,
+ this.clientPairedSecret_);
this.clientSession_.logHostOfflineErrors(!this.refreshHostJidIfOffline_);
this.clientSession_.setOnStateChange(this.onStateChange_.bind(this));
this.clientSession_.createPluginAndConnect(this.pluginParent_);
@@ -408,7 +441,8 @@ remoting.SessionConnector.prototype.onHostListRefresh_ = function(success) {
if (success) {
var host = remoting.hostList.getHostForId(this.hostId_);
if (host) {
- this.connectMe2Me(host, this.fetchPin_, this.fetchThirdPartyToken_);
+ this.connectMe2Me(host, this.fetchPin_, this.fetchThirdPartyToken_,
+ this.clientPairingId_, this.clientPairedSecret_);
return;
}
}
@@ -471,4 +505,4 @@ remoting.SessionConnector.prototype.normalizeAccessCode_ =
function(accessCode) {
// Trim whitespace.
return accessCode.replace(/\s/g, '');
-}; \ No newline at end of file
+};