1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/host/plugin/host_script_object.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "remoting/base/auth_token_util.h"
15 #include "remoting/base/auto_thread.h"
16 #include "remoting/base/logging.h"
17 #include "remoting/base/resources.h"
18 #include "remoting/base/rsa_key_pair.h"
19 #include "remoting/host/chromoting_host_context.h"
20 #include "remoting/host/host_config.h"
21 #include "remoting/host/pairing_registry_delegate.h"
22 #include "remoting/host/pin_hash.h"
23 #include "remoting/host/plugin/host_log_handler.h"
24 #include "remoting/host/policy_hack/policy_watcher.h"
25 #include "remoting/host/service_urls.h"
26 #include "third_party/npapi/bindings/npapi.h"
27 #include "third_party/npapi/bindings/npfunctions.h"
28 #include "third_party/npapi/bindings/npruntime.h"
34 const char* kAttrNameAccessCode = "accessCode";
35 const char* kAttrNameAccessCodeLifetime = "accessCodeLifetime";
36 const char* kAttrNameClient = "client";
37 const char* kAttrNameDaemonState = "daemonState";
38 const char* kAttrNameState = "state";
39 const char* kAttrNameLogDebugInfo = "logDebugInfo";
40 const char* kAttrNameOnNatTraversalPolicyChanged =
41 "onNatTraversalPolicyChanged";
42 const char* kAttrNameOnStateChanged = "onStateChanged";
43 const char* kAttrNameXmppServerAddress = "xmppServerAddress";
44 const char* kAttrNameXmppServerUseTls = "xmppServerUseTls";
45 const char* kAttrNameDirectoryBotJid = "directoryBotJid";
46 const char* kAttrNameSupportedFeatures = "supportedFeatures";
47 const char* kFuncNameConnect = "connect";
48 const char* kFuncNameDisconnect = "disconnect";
49 const char* kFuncNameLocalize = "localize";
50 const char* kFuncNameClearPairedClients = "clearPairedClients";
51 const char* kFuncNameDeletePairedClient = "deletePairedClient";
52 const char* kFuncNameGetHostName = "getHostName";
53 const char* kFuncNameGetPinHash = "getPinHash";
54 const char* kFuncNameGenerateKeyPair = "generateKeyPair";
55 const char* kFuncNameUpdateDaemonConfig = "updateDaemonConfig";
56 const char* kFuncNameGetDaemonConfig = "getDaemonConfig";
57 const char* kFuncNameGetDaemonVersion = "getDaemonVersion";
58 const char* kFuncNameGetPairedClients = "getPairedClients";
59 const char* kFuncNameGetUsageStatsConsent = "getUsageStatsConsent";
60 const char* kFuncNameInstallHost = "installHost";
61 const char* kFuncNameStartDaemon = "startDaemon";
62 const char* kFuncNameStopDaemon = "stopDaemon";
65 const char* kAttrNameDisconnected = "DISCONNECTED";
66 const char* kAttrNameStarting = "STARTING";
67 const char* kAttrNameRequestedAccessCode = "REQUESTED_ACCESS_CODE";
68 const char* kAttrNameReceivedAccessCode = "RECEIVED_ACCESS_CODE";
69 const char* kAttrNameConnected = "CONNECTED";
70 const char* kAttrNameDisconnecting = "DISCONNECTING";
71 const char* kAttrNameError = "ERROR";
72 const char* kAttrNameInvalidDomainError = "INVALID_DOMAIN_ERROR";
74 // Space separated list of features supported in addition to the base protocol.
75 const char* kSupportedFeatures = "pairingRegistry";
79 HostNPScriptObject::HostNPScriptObject(
82 scoped_refptr<AutoThreadTaskRunner> plugin_task_runner)
85 plugin_task_runner_(plugin_task_runner),
86 am_currently_logging_(false),
87 state_(kDisconnected),
89 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
91 weak_ptr_ = weak_factory_.GetWeakPtr();
93 // Set the thread task runner for the plugin thread so that timers and other
94 // code using |base::ThreadTaskRunnerHandle| could be used on the plugin
97 // If component build is used, Chrome and the plugin may end up sharing base
98 // binary. This means that the instance of |base::ThreadTaskRunnerHandle|
99 // created by Chrome for the current thread is shared as well. This routinely
100 // happens in the development setting so the below check for
101 // |!base::ThreadTaskRunnerHandle::IsSet()| is a hack/workaround allowing this
102 // configuration to work. It lets the plugin to access Chrome's message loop
103 // directly via |base::ThreadTaskRunnerHandle|. This is safe as long as both
104 // Chrome and the plugin are built from the same version of the sources.
105 if (!base::ThreadTaskRunnerHandle::IsSet()) {
106 plugin_task_runner_handle_.reset(
107 new base::ThreadTaskRunnerHandle(plugin_task_runner_));
110 daemon_controller_ = DaemonController::Create();
112 ServiceUrls* service_urls = ServiceUrls::GetInstance();
113 bool xmpp_server_valid = net::ParseHostAndPort(
114 service_urls->xmpp_server_address(),
115 &xmpp_server_config_.host, &xmpp_server_config_.port);
116 // For the plugin, this is always the default address, which must be valid.
117 DCHECK(xmpp_server_valid);
118 xmpp_server_config_.use_tls = service_urls->xmpp_server_use_tls();
119 directory_bot_jid_ = service_urls->directory_bot_jid();
121 // Create worker thread for encryption key generation and loading the paired
123 worker_thread_ = AutoThread::Create("ChromotingWorkerThread",
124 plugin_task_runner_);
126 pairing_registry_ = CreatePairingRegistry(worker_thread_);
129 HostNPScriptObject::~HostNPScriptObject() {
130 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
132 HostLogHandler::UnregisterLoggingScriptObject(this);
134 // Stop the It2Me host if the caller forgot to.
135 if (it2me_host_.get()) {
136 it2me_host_->Disconnect();
141 bool HostNPScriptObject::HasMethod(const std::string& method_name) {
142 VLOG(2) << "HasMethod " << method_name;
143 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
144 return (method_name == kFuncNameConnect ||
145 method_name == kFuncNameDisconnect ||
146 method_name == kFuncNameLocalize ||
147 method_name == kFuncNameClearPairedClients ||
148 method_name == kFuncNameDeletePairedClient ||
149 method_name == kFuncNameGetHostName ||
150 method_name == kFuncNameGetPinHash ||
151 method_name == kFuncNameGenerateKeyPair ||
152 method_name == kFuncNameUpdateDaemonConfig ||
153 method_name == kFuncNameGetDaemonConfig ||
154 method_name == kFuncNameGetDaemonVersion ||
155 method_name == kFuncNameGetPairedClients ||
156 method_name == kFuncNameGetUsageStatsConsent ||
157 method_name == kFuncNameInstallHost ||
158 method_name == kFuncNameStartDaemon ||
159 method_name == kFuncNameStopDaemon);
162 bool HostNPScriptObject::InvokeDefault(const NPVariant* args,
165 VLOG(2) << "InvokeDefault";
166 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
167 SetException("exception during default invocation");
171 bool HostNPScriptObject::Invoke(const std::string& method_name,
172 const NPVariant* args,
175 VLOG(2) << "Invoke " << method_name;
176 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
177 if (method_name == kFuncNameConnect) {
178 return Connect(args, arg_count, result);
179 } else if (method_name == kFuncNameDisconnect) {
180 return Disconnect(args, arg_count, result);
181 } else if (method_name == kFuncNameLocalize) {
182 return Localize(args, arg_count, result);
183 } else if (method_name == kFuncNameClearPairedClients) {
184 return ClearPairedClients(args, arg_count, result);
185 } else if (method_name == kFuncNameDeletePairedClient) {
186 return DeletePairedClient(args, arg_count, result);
187 } else if (method_name == kFuncNameGetHostName) {
188 return GetHostName(args, arg_count, result);
189 } else if (method_name == kFuncNameGetPinHash) {
190 return GetPinHash(args, arg_count, result);
191 } else if (method_name == kFuncNameGenerateKeyPair) {
192 return GenerateKeyPair(args, arg_count, result);
193 } else if (method_name == kFuncNameUpdateDaemonConfig) {
194 return UpdateDaemonConfig(args, arg_count, result);
195 } else if (method_name == kFuncNameGetDaemonConfig) {
196 return GetDaemonConfig(args, arg_count, result);
197 } else if (method_name == kFuncNameGetDaemonVersion) {
198 return GetDaemonVersion(args, arg_count, result);
199 } else if (method_name == kFuncNameGetPairedClients) {
200 return GetPairedClients(args, arg_count, result);
201 } else if (method_name == kFuncNameGetUsageStatsConsent) {
202 return GetUsageStatsConsent(args, arg_count, result);
203 } else if (method_name == kFuncNameInstallHost) {
204 return InstallHost(args, arg_count, result);
205 } else if (method_name == kFuncNameStartDaemon) {
206 return StartDaemon(args, arg_count, result);
207 } else if (method_name == kFuncNameStopDaemon) {
208 return StopDaemon(args, arg_count, result);
210 SetException("Invoke: unknown method " + method_name);
215 bool HostNPScriptObject::HasProperty(const std::string& property_name) {
216 VLOG(2) << "HasProperty " << property_name;
217 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
218 return (property_name == kAttrNameAccessCode ||
219 property_name == kAttrNameAccessCodeLifetime ||
220 property_name == kAttrNameClient ||
221 property_name == kAttrNameDaemonState ||
222 property_name == kAttrNameState ||
223 property_name == kAttrNameLogDebugInfo ||
224 property_name == kAttrNameOnNatTraversalPolicyChanged ||
225 property_name == kAttrNameOnStateChanged ||
226 property_name == kAttrNameDisconnected ||
227 property_name == kAttrNameStarting ||
228 property_name == kAttrNameRequestedAccessCode ||
229 property_name == kAttrNameReceivedAccessCode ||
230 property_name == kAttrNameConnected ||
231 property_name == kAttrNameDisconnecting ||
232 property_name == kAttrNameError ||
233 property_name == kAttrNameXmppServerAddress ||
234 property_name == kAttrNameXmppServerUseTls ||
235 property_name == kAttrNameDirectoryBotJid ||
236 property_name == kAttrNameSupportedFeatures);
239 bool HostNPScriptObject::GetProperty(const std::string& property_name,
241 VLOG(2) << "GetProperty " << property_name;
242 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
244 SetException("GetProperty: NULL result");
248 if (property_name == kAttrNameOnNatTraversalPolicyChanged) {
249 OBJECT_TO_NPVARIANT(on_nat_traversal_policy_changed_func_.get(), *result);
251 } else if (property_name == kAttrNameOnStateChanged) {
252 OBJECT_TO_NPVARIANT(on_state_changed_func_.get(), *result);
254 } else if (property_name == kAttrNameLogDebugInfo) {
255 OBJECT_TO_NPVARIANT(log_debug_info_func_.get(), *result);
257 } else if (property_name == kAttrNameState) {
258 INT32_TO_NPVARIANT(state_, *result);
260 } else if (property_name == kAttrNameAccessCode) {
261 *result = NPVariantFromString(access_code_);
263 } else if (property_name == kAttrNameAccessCodeLifetime) {
264 INT32_TO_NPVARIANT(access_code_lifetime_.InSeconds(), *result);
266 } else if (property_name == kAttrNameClient) {
267 *result = NPVariantFromString(client_username_);
269 } else if (property_name == kAttrNameDaemonState) {
270 INT32_TO_NPVARIANT(daemon_controller_->GetState(), *result);
272 } else if (property_name == kAttrNameDisconnected) {
273 INT32_TO_NPVARIANT(kDisconnected, *result);
275 } else if (property_name == kAttrNameStarting) {
276 INT32_TO_NPVARIANT(kStarting, *result);
278 } else if (property_name == kAttrNameRequestedAccessCode) {
279 INT32_TO_NPVARIANT(kRequestedAccessCode, *result);
281 } else if (property_name == kAttrNameReceivedAccessCode) {
282 INT32_TO_NPVARIANT(kReceivedAccessCode, *result);
284 } else if (property_name == kAttrNameConnected) {
285 INT32_TO_NPVARIANT(kConnected, *result);
287 } else if (property_name == kAttrNameDisconnecting) {
288 INT32_TO_NPVARIANT(kDisconnecting, *result);
290 } else if (property_name == kAttrNameError) {
291 INT32_TO_NPVARIANT(kError, *result);
293 } else if (property_name == kAttrNameInvalidDomainError) {
294 INT32_TO_NPVARIANT(kInvalidDomainError, *result);
296 } else if (property_name == kAttrNameXmppServerAddress) {
297 *result = NPVariantFromString(base::StringPrintf(
298 "%s:%u", xmpp_server_config_.host.c_str(), xmpp_server_config_.port));
300 } else if (property_name == kAttrNameXmppServerUseTls) {
301 BOOLEAN_TO_NPVARIANT(xmpp_server_config_.use_tls, *result);
303 } else if (property_name == kAttrNameDirectoryBotJid) {
304 *result = NPVariantFromString(directory_bot_jid_);
306 } else if (property_name == kAttrNameSupportedFeatures) {
307 *result = NPVariantFromString(kSupportedFeatures);
310 SetException("GetProperty: unsupported property " + property_name);
315 bool HostNPScriptObject::SetProperty(const std::string& property_name,
316 const NPVariant* value) {
317 VLOG(2) << "SetProperty " << property_name;
318 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
320 if (property_name == kAttrNameOnNatTraversalPolicyChanged) {
321 if (NPVARIANT_IS_OBJECT(*value)) {
322 on_nat_traversal_policy_changed_func_ = NPVARIANT_TO_OBJECT(*value);
323 if (it2me_host_.get()) {
324 // Ask the It2Me host to notify the web-app of the policy.
325 it2me_host_->RequestNatPolicy();
329 SetException("SetProperty: unexpected type for property " +
335 if (property_name == kAttrNameOnStateChanged) {
336 if (NPVARIANT_IS_OBJECT(*value)) {
337 on_state_changed_func_ = NPVARIANT_TO_OBJECT(*value);
340 SetException("SetProperty: unexpected type for property " +
346 if (property_name == kAttrNameLogDebugInfo) {
347 if (NPVARIANT_IS_OBJECT(*value)) {
348 log_debug_info_func_ = NPVARIANT_TO_OBJECT(*value);
349 HostLogHandler::RegisterLoggingScriptObject(this);
352 SetException("SetProperty: unexpected type for property " +
359 if (property_name == kAttrNameXmppServerAddress) {
360 if (NPVARIANT_IS_STRING(*value)) {
361 std::string address = StringFromNPVariant(*value);
362 bool xmpp_server_valid = net::ParseHostAndPort(
363 address, &xmpp_server_config_.host, &xmpp_server_config_.port);
364 if (xmpp_server_valid) {
367 SetException("SetProperty: invalid value for property " +
371 SetException("SetProperty: unexpected type for property " +
377 if (property_name == kAttrNameXmppServerUseTls) {
378 if (NPVARIANT_IS_BOOLEAN(*value)) {
379 xmpp_server_config_.use_tls = NPVARIANT_TO_BOOLEAN(*value);
382 SetException("SetProperty: unexpected type for property " +
388 if (property_name == kAttrNameDirectoryBotJid) {
389 if (NPVARIANT_IS_STRING(*value)) {
390 directory_bot_jid_ = StringFromNPVariant(*value);
393 SetException("SetProperty: unexpected type for property " +
398 #endif // !defined(NDEBUG)
403 bool HostNPScriptObject::RemoveProperty(const std::string& property_name) {
404 VLOG(2) << "RemoveProperty " << property_name;
405 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
409 bool HostNPScriptObject::Enumerate(std::vector<std::string>* values) {
410 VLOG(2) << "Enumerate";
411 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
412 const char* entries[] = {
415 kAttrNameLogDebugInfo,
416 kAttrNameOnStateChanged,
417 kAttrNameDisconnected,
419 kAttrNameRequestedAccessCode,
420 kAttrNameReceivedAccessCode,
422 kAttrNameDisconnecting,
424 kAttrNameXmppServerAddress,
425 kAttrNameXmppServerUseTls,
426 kAttrNameDirectoryBotJid,
430 kFuncNameClearPairedClients,
431 kFuncNameDeletePairedClient,
432 kFuncNameGetHostName,
434 kFuncNameGenerateKeyPair,
435 kFuncNameUpdateDaemonConfig,
436 kFuncNameGetDaemonConfig,
437 kFuncNameGetDaemonVersion,
438 kFuncNameGetPairedClients,
439 kFuncNameGetUsageStatsConsent,
440 kFuncNameInstallHost,
441 kFuncNameStartDaemon,
444 for (size_t i = 0; i < arraysize(entries); ++i) {
445 values->push_back(entries[i]);
450 // string username, string auth_token
451 bool HostNPScriptObject::Connect(const NPVariant* args,
454 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
456 HOST_LOG << "Connecting...";
458 if (arg_count != 2) {
459 SetException("connect: bad number of arguments");
463 if (it2me_host_.get()) {
464 SetException("connect: can be called only when disconnected");
468 XmppSignalStrategy::XmppServerConfig xmpp_config = xmpp_server_config_;
470 xmpp_config.username = StringFromNPVariant(args[0]);
471 if (xmpp_config.username.empty()) {
472 SetException("connect: bad username argument");
476 std::string auth_service_with_token = StringFromNPVariant(args[1]);
477 ParseAuthTokenWithService(auth_service_with_token, &xmpp_config.auth_token,
478 &xmpp_config.auth_service);
479 if (xmpp_config.auth_token.empty()) {
480 SetException("connect: auth_service_with_token argument has empty token");
484 // Create a host context to manage the threads for the it2me host.
485 // The plugin, rather than the It2MeHost object, owns and maintains the
486 // lifetime of the host context.
488 ChromotingHostContext::Create(plugin_task_runner_).release());
489 if (!host_context_) {
490 SetException("connect: failed to start threads");
494 // Create the It2Me host and start connecting.
495 scoped_ptr<It2MeHostFactory> factory(new It2MeHostFactory());
496 it2me_host_ = factory->CreateIt2MeHost(
497 host_context_.get(), plugin_task_runner_, weak_ptr_,
498 xmpp_config, directory_bot_jid_);
499 it2me_host_->Connect();
504 bool HostNPScriptObject::Disconnect(const NPVariant* args,
507 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
508 if (arg_count != 0) {
509 SetException("disconnect: bad number of arguments");
513 if (it2me_host_.get()) {
514 it2me_host_->Disconnect();
521 bool HostNPScriptObject::Localize(const NPVariant* args,
524 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
525 if (arg_count != 1) {
526 SetException("localize: bad number of arguments");
530 if (NPVARIANT_IS_OBJECT(args[0])) {
531 ScopedRefNPObject localize_func(NPVARIANT_TO_OBJECT(args[0]));
532 LocalizeStrings(localize_func.get());
535 SetException("localize: unexpected type for argument 1");
540 bool HostNPScriptObject::ClearPairedClients(const NPVariant* args,
543 if (arg_count != 1) {
544 SetException("clearPairedClients: bad number of arguments");
548 if (!NPVARIANT_IS_OBJECT(args[0])) {
549 SetException("clearPairedClients: invalid callback parameter");
553 scoped_ptr<ScopedRefNPObject> callback_obj(
554 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
555 if (pairing_registry_) {
556 pairing_registry_->ClearAllPairings(
557 base::Bind(&HostNPScriptObject::InvokeBooleanCallback, weak_ptr_,
558 base::Passed(&callback_obj)));
560 InvokeBooleanCallback(callback_obj.Pass(), false);
566 bool HostNPScriptObject::DeletePairedClient(const NPVariant* args,
569 if (arg_count != 2) {
570 SetException("deletePairedClient: bad number of arguments");
574 if (!NPVARIANT_IS_STRING(args[0])) {
575 SetException("deletePairedClient: bad clientId parameter");
579 if (!NPVARIANT_IS_OBJECT(args[1])) {
580 SetException("deletePairedClient: invalid callback parameter");
584 std::string client_id = StringFromNPVariant(args[0]);
585 scoped_ptr<ScopedRefNPObject> callback_obj(
586 new ScopedRefNPObject(ObjectFromNPVariant(args[1])));
587 if (pairing_registry_) {
588 pairing_registry_->DeletePairing(
590 base::Bind(&HostNPScriptObject::InvokeBooleanCallback,
591 weak_ptr_, base::Passed(&callback_obj)));
593 InvokeBooleanCallback(callback_obj.Pass(), false);
599 bool HostNPScriptObject::GetHostName(const NPVariant* args,
602 if (arg_count != 1) {
603 SetException("getHostName: bad number of arguments");
607 ScopedRefNPObject callback_obj(ObjectFromNPVariant(args[0]));
608 if (!callback_obj.get()) {
609 SetException("getHostName: invalid callback parameter");
613 NPVariant host_name_val = NPVariantFromString(net::GetHostName());
614 InvokeAndIgnoreResult(callback_obj, &host_name_val, 1);
615 g_npnetscape_funcs->releasevariantvalue(&host_name_val);
620 bool HostNPScriptObject::GetPinHash(const NPVariant* args,
623 if (arg_count != 3) {
624 SetException("getPinHash: bad number of arguments");
628 std::string host_id = StringFromNPVariant(args[0]);
629 if (host_id.empty()) {
630 SetException("getPinHash: bad hostId parameter");
634 if (!NPVARIANT_IS_STRING(args[1])) {
635 SetException("getPinHash: bad pin parameter");
638 std::string pin = StringFromNPVariant(args[1]);
640 ScopedRefNPObject callback_obj(ObjectFromNPVariant(args[2]));
641 if (!callback_obj.get()) {
642 SetException("getPinHash: invalid callback parameter");
646 NPVariant pin_hash_val = NPVariantFromString(
647 remoting::MakeHostPinHash(host_id, pin));
648 InvokeAndIgnoreResult(callback_obj, &pin_hash_val, 1);
649 g_npnetscape_funcs->releasevariantvalue(&pin_hash_val);
654 bool HostNPScriptObject::GenerateKeyPair(const NPVariant* args,
657 if (arg_count != 1) {
658 SetException("generateKeyPair: bad number of arguments");
662 scoped_ptr<ScopedRefNPObject> callback_obj(
663 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
664 if (!callback_obj->get()) {
665 SetException("generateKeyPair: invalid callback parameter");
669 base::Callback<void (const std::string&,
670 const std::string&)> wrapped_callback =
671 base::Bind(&HostNPScriptObject::InvokeGenerateKeyPairCallback, weak_ptr_,
672 base::Passed(&callback_obj));
673 worker_thread_->PostTask(
674 FROM_HERE, base::Bind(&HostNPScriptObject::DoGenerateKeyPair,
675 plugin_task_runner_, wrapped_callback));
679 bool HostNPScriptObject::UpdateDaemonConfig(const NPVariant* args,
682 if (arg_count != 2) {
683 SetException("updateDaemonConfig: bad number of arguments");
687 std::string config_str = StringFromNPVariant(args[0]);
688 scoped_ptr<base::Value> config(
689 base::JSONReader::Read(config_str, base::JSON_ALLOW_TRAILING_COMMAS));
690 if (config_str.empty() || !config.get() ||
691 !config->IsType(base::Value::TYPE_DICTIONARY)) {
692 SetException("updateDaemonConfig: bad config parameter");
695 scoped_ptr<base::DictionaryValue> config_dict(
696 reinterpret_cast<base::DictionaryValue*>(config.release()));
698 scoped_ptr<ScopedRefNPObject> callback_obj(
699 new ScopedRefNPObject(ObjectFromNPVariant(args[1])));
700 if (!callback_obj->get()) {
701 SetException("updateDaemonConfig: invalid callback parameter");
705 if (config_dict->HasKey(kHostIdConfigPath) ||
706 config_dict->HasKey(kXmppLoginConfigPath)) {
707 SetException("updateDaemonConfig: trying to update immutable config "
712 daemon_controller_->UpdateConfig(
714 base::Bind(&HostNPScriptObject::InvokeAsyncResultCallback, weak_ptr_,
715 base::Passed(&callback_obj)));
719 bool HostNPScriptObject::GetDaemonConfig(const NPVariant* args,
722 if (arg_count != 1) {
723 SetException("getDaemonConfig: bad number of arguments");
727 scoped_ptr<ScopedRefNPObject> callback_obj(
728 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
729 if (!callback_obj->get()) {
730 SetException("getDaemonConfig: invalid callback parameter");
734 daemon_controller_->GetConfig(
735 base::Bind(&HostNPScriptObject::InvokeGetDaemonConfigCallback, weak_ptr_,
736 base::Passed(&callback_obj)));
740 bool HostNPScriptObject::GetDaemonVersion(const NPVariant* args,
743 if (arg_count != 1) {
744 SetException("getDaemonVersion: bad number of arguments");
748 scoped_ptr<ScopedRefNPObject> callback_obj(
749 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
750 if (!callback_obj->get()) {
751 SetException("getDaemonVersion: invalid callback parameter");
755 daemon_controller_->GetVersion(
756 base::Bind(&HostNPScriptObject::InvokeGetDaemonVersionCallback, weak_ptr_,
757 base::Passed(&callback_obj)));
762 bool HostNPScriptObject::GetPairedClients(const NPVariant* args,
765 if (arg_count != 1) {
766 SetException("getPairedClients: bad number of arguments");
770 scoped_ptr<ScopedRefNPObject> callback_obj(
771 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
772 if (!callback_obj->get()) {
773 SetException("getPairedClients: invalid callback parameter");
777 if (pairing_registry_) {
778 pairing_registry_->GetAllPairings(
779 base::Bind(&HostNPScriptObject::InvokeGetPairedClientsCallback,
780 weak_ptr_, base::Passed(&callback_obj)));
782 scoped_ptr<base::ListValue> no_paired_clients(new base::ListValue);
783 InvokeGetPairedClientsCallback(callback_obj.Pass(),
784 no_paired_clients.Pass());
789 bool HostNPScriptObject::GetUsageStatsConsent(const NPVariant* args,
792 if (arg_count != 1) {
793 SetException("getUsageStatsConsent: bad number of arguments");
797 scoped_ptr<ScopedRefNPObject> callback_obj(
798 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
799 if (!callback_obj->get()) {
800 SetException("getUsageStatsConsent: invalid callback parameter");
804 daemon_controller_->GetUsageStatsConsent(
805 base::Bind(&HostNPScriptObject::InvokeGetUsageStatsConsentCallback,
806 weak_ptr_, base::Passed(&callback_obj)));
810 bool HostNPScriptObject::InstallHost(const NPVariant* args,
813 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
815 if (arg_count != 1) {
816 SetException("installHost: bad number of arguments");
820 scoped_ptr<ScopedRefNPObject> callback_obj(
821 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
822 if (!callback_obj->get()) {
823 SetException("installHost: invalid callback parameter");
827 daemon_controller_->InstallHost(
828 base::Bind(&HostNPScriptObject::InvokeAsyncResultCallback, weak_ptr_,
829 base::Passed(&callback_obj)));
833 bool HostNPScriptObject::StartDaemon(const NPVariant* args,
836 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
838 if (arg_count != 3) {
839 SetException("startDaemon: bad number of arguments");
843 std::string config_str = StringFromNPVariant(args[0]);
844 scoped_ptr<base::Value> config(
845 base::JSONReader::Read(config_str, base::JSON_ALLOW_TRAILING_COMMAS));
846 if (config_str.empty() || !config.get() ||
847 !config->IsType(base::Value::TYPE_DICTIONARY)) {
848 SetException("startDaemon: bad config parameter");
851 scoped_ptr<base::DictionaryValue> config_dict(
852 reinterpret_cast<base::DictionaryValue*>(config.release()));
854 if (!NPVARIANT_IS_BOOLEAN(args[1])) {
855 SetException("startDaemon: invalid consent parameter");
859 scoped_ptr<ScopedRefNPObject> callback_obj(
860 new ScopedRefNPObject(ObjectFromNPVariant(args[2])));
861 if (!callback_obj->get()) {
862 SetException("startDaemon: invalid callback parameter");
866 daemon_controller_->SetConfigAndStart(
868 NPVARIANT_TO_BOOLEAN(args[1]),
869 base::Bind(&HostNPScriptObject::InvokeAsyncResultCallback, weak_ptr_,
870 base::Passed(&callback_obj)));
874 bool HostNPScriptObject::StopDaemon(const NPVariant* args,
877 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
879 if (arg_count != 1) {
880 SetException("stopDaemon: bad number of arguments");
884 scoped_ptr<ScopedRefNPObject> callback_obj(
885 new ScopedRefNPObject(ObjectFromNPVariant(args[0])));
886 if (!callback_obj->get()) {
887 SetException("stopDaemon: invalid callback parameter");
891 daemon_controller_->Stop(
892 base::Bind(&HostNPScriptObject::InvokeAsyncResultCallback, weak_ptr_,
893 base::Passed(&callback_obj)));
897 void HostNPScriptObject::OnStateChanged(It2MeHostState state) {
898 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
902 if (state_ == kDisconnected)
903 client_username_.clear();
905 if (on_state_changed_func_.get()) {
907 INT32_TO_NPVARIANT(state, state_var);
908 InvokeAndIgnoreResult(on_state_changed_func_, &state_var, 1);
912 void HostNPScriptObject::OnNatPolicyChanged(bool nat_traversal_enabled) {
913 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
915 if (on_nat_traversal_policy_changed_func_.get()) {
917 BOOLEAN_TO_NPVARIANT(nat_traversal_enabled, policy);
918 InvokeAndIgnoreResult(on_nat_traversal_policy_changed_func_,
923 // Stores the Access Code for the web-app to query.
924 void HostNPScriptObject::OnStoreAccessCode(
925 const std::string& access_code, base::TimeDelta access_code_lifetime) {
926 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
928 access_code_ = access_code;
929 access_code_lifetime_ = access_code_lifetime;
932 // Stores the client user's name for the web-app to query.
933 void HostNPScriptObject::OnClientAuthenticated(
934 const std::string& client_username) {
935 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
937 client_username_ = client_username;
940 void HostNPScriptObject::PostLogDebugInfo(const std::string& message) {
941 if (plugin_task_runner_->BelongsToCurrentThread()) {
942 // Make sure we're not currently processing a log message.
943 // We only need to check this if we're on the plugin thread.
944 if (am_currently_logging_)
948 // Always post (even if we're already on the correct thread) so that debug
949 // log messages are shown in the correct order.
950 plugin_task_runner_->PostTask(
951 FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo,
952 weak_ptr_, message));
955 void HostNPScriptObject::SetWindow(NPWindow* np_window) {
956 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
958 daemon_controller_->SetWindow(np_window->window);
961 void HostNPScriptObject::LocalizeStrings(NPObject* localize_func) {
962 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
964 // Reload resources for the current locale. The default UI locale is used on
967 base::string16 ui_locale;
968 LocalizeString(localize_func, "@@ui_locale", &ui_locale);
969 remoting::LoadResources(base::UTF16ToUTF8(ui_locale));
970 #endif // !defined(OS_WIN)
973 bool HostNPScriptObject::LocalizeString(NPObject* localize_func,
975 base::string16* result) {
976 return LocalizeStringWithSubstitution(localize_func, tag, NULL, result);
979 bool HostNPScriptObject::LocalizeStringWithSubstitution(
980 NPObject* localize_func,
982 const char* substitution,
983 base::string16* result) {
984 int argc = substitution ? 2 : 1;
985 scoped_ptr<NPVariant[]> args(new NPVariant[argc]);
986 STRINGZ_TO_NPVARIANT(tag, args[0]);
988 STRINGZ_TO_NPVARIANT(substitution, args[1]);
991 bool is_good = g_npnetscape_funcs->invokeDefault(
992 plugin_, localize_func, args.get(), argc, &np_result);
994 LOG(ERROR) << "Localization failed for " << tag;
997 std::string translation = StringFromNPVariant(np_result);
998 g_npnetscape_funcs->releasevariantvalue(&np_result);
999 if (translation.empty()) {
1000 LOG(ERROR) << "Missing translation for " << tag;
1003 *result = base::UTF8ToUTF16(translation);
1008 void HostNPScriptObject::DoGenerateKeyPair(
1009 const scoped_refptr<AutoThreadTaskRunner>& plugin_task_runner,
1010 const base::Callback<void (const std::string&,
1011 const std::string&)>& callback) {
1012 scoped_refptr<RsaKeyPair> key_pair = RsaKeyPair::Generate();
1013 plugin_task_runner->PostTask(FROM_HERE,
1014 base::Bind(callback, key_pair->ToString(),
1015 key_pair->GetPublicKey()));
1018 void HostNPScriptObject::InvokeGenerateKeyPairCallback(
1019 scoped_ptr<ScopedRefNPObject> callback,
1020 const std::string& private_key,
1021 const std::string& public_key) {
1022 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1024 NPVariant params[2];
1025 params[0] = NPVariantFromString(private_key);
1026 params[1] = NPVariantFromString(public_key);
1027 InvokeAndIgnoreResult(*callback, params, arraysize(params));
1028 g_npnetscape_funcs->releasevariantvalue(&(params[0]));
1029 g_npnetscape_funcs->releasevariantvalue(&(params[1]));
1032 void HostNPScriptObject::InvokeAsyncResultCallback(
1033 scoped_ptr<ScopedRefNPObject> callback,
1034 DaemonController::AsyncResult result) {
1035 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1037 NPVariant result_var;
1038 INT32_TO_NPVARIANT(static_cast<int32>(result), result_var);
1039 InvokeAndIgnoreResult(*callback, &result_var, 1);
1040 g_npnetscape_funcs->releasevariantvalue(&result_var);
1043 void HostNPScriptObject::InvokeBooleanCallback(
1044 scoped_ptr<ScopedRefNPObject> callback, bool result) {
1045 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1047 NPVariant result_var;
1048 BOOLEAN_TO_NPVARIANT(result, result_var);
1049 InvokeAndIgnoreResult(*callback, &result_var, 1);
1050 g_npnetscape_funcs->releasevariantvalue(&result_var);
1053 void HostNPScriptObject::InvokeGetDaemonConfigCallback(
1054 scoped_ptr<ScopedRefNPObject> callback,
1055 scoped_ptr<base::DictionaryValue> config) {
1056 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1058 // There is no easy way to create a dictionary from an NPAPI plugin
1059 // so we have to serialize the dictionary to pass it to JavaScript.
1060 std::string config_str;
1062 base::JSONWriter::Write(config.get(), &config_str);
1064 NPVariant config_val = NPVariantFromString(config_str);
1065 InvokeAndIgnoreResult(*callback, &config_val, 1);
1066 g_npnetscape_funcs->releasevariantvalue(&config_val);
1069 void HostNPScriptObject::InvokeGetDaemonVersionCallback(
1070 scoped_ptr<ScopedRefNPObject> callback, const std::string& version) {
1071 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1073 NPVariant version_val = NPVariantFromString(version);
1074 InvokeAndIgnoreResult(*callback, &version_val, 1);
1075 g_npnetscape_funcs->releasevariantvalue(&version_val);
1078 void HostNPScriptObject::InvokeGetPairedClientsCallback(
1079 scoped_ptr<ScopedRefNPObject> callback,
1080 scoped_ptr<base::ListValue> paired_clients) {
1081 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1083 std::string paired_clients_json;
1084 base::JSONWriter::Write(paired_clients.get(), &paired_clients_json);
1086 NPVariant paired_clients_val = NPVariantFromString(paired_clients_json);
1087 InvokeAndIgnoreResult(*callback, &paired_clients_val, 1);
1088 g_npnetscape_funcs->releasevariantvalue(&paired_clients_val);
1091 void HostNPScriptObject::InvokeGetUsageStatsConsentCallback(
1092 scoped_ptr<ScopedRefNPObject> callback,
1093 const DaemonController::UsageStatsConsent& consent) {
1094 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1096 NPVariant params[3];
1097 BOOLEAN_TO_NPVARIANT(consent.supported, params[0]);
1098 BOOLEAN_TO_NPVARIANT(consent.allowed, params[1]);
1099 BOOLEAN_TO_NPVARIANT(consent.set_by_policy, params[2]);
1100 InvokeAndIgnoreResult(*callback, params, arraysize(params));
1101 g_npnetscape_funcs->releasevariantvalue(&(params[0]));
1102 g_npnetscape_funcs->releasevariantvalue(&(params[1]));
1103 g_npnetscape_funcs->releasevariantvalue(&(params[2]));
1106 void HostNPScriptObject::LogDebugInfo(const std::string& message) {
1107 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1109 if (log_debug_info_func_.get()) {
1110 am_currently_logging_ = true;
1111 NPVariant log_message;
1112 STRINGZ_TO_NPVARIANT(message.c_str(), log_message);
1113 bool is_good = InvokeAndIgnoreResult(log_debug_info_func_,
1116 LOG(ERROR) << "ERROR - LogDebugInfo failed\n";
1118 am_currently_logging_ = false;
1122 bool HostNPScriptObject::InvokeAndIgnoreResult(const ScopedRefNPObject& func,
1123 const NPVariant* args,
1124 uint32_t arg_count) {
1125 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1127 NPVariant np_result;
1128 bool is_good = g_npnetscape_funcs->invokeDefault(plugin_, func.get(), args,
1129 arg_count, &np_result);
1131 g_npnetscape_funcs->releasevariantvalue(&np_result);
1136 void HostNPScriptObject::SetException(const std::string& exception_string) {
1137 DCHECK(plugin_task_runner_->BelongsToCurrentThread());
1139 g_npnetscape_funcs->setexception(parent_, exception_string.c_str());
1140 HOST_LOG << exception_string;
1143 } // namespace remoting