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.
7 /** @suppress {duplicate} */
8 var remoting
= remoting
|| {};
11 remoting
.HostController = function() {
12 /** @type {remoting.HostController} */
15 /** @type {boolean} @private */
16 this.pluginSupported_
= true;
18 /** @type {remoting.HostNativeMessaging} @private */
19 this.plugin_
= new remoting
.HostNativeMessaging();
21 /** @param {boolean} success */
22 var onNativeMessagingInit = function(success
) {
24 console
.log('Native Messaging supported.');
26 console
.log('Native Messaging unsupported, falling back to NPAPI.');
27 var plugin
= remoting
.HostSession
.createPlugin();
28 that
.plugin_
= new remoting
.HostPluginWrapper(plugin
);
29 /** @type {HTMLElement} @private */
30 var container
= document
.getElementById('daemon-plugin-container');
31 container
.appendChild(plugin
);
34 /** @param {string} version */
35 var printVersion = function(version
) {
37 console
.log('Host not installed.');
39 console
.log('Host version: ' + version
);
42 that
.pluginSupported_
= true;
44 that
.plugin_
.getDaemonVersion(printVersion
);
46 console
.log('Host version not available.');
47 that
.pluginSupported_
= false;
51 this.plugin_
.initialize(onNativeMessagingInit
);
54 // Note that the values in the enums below are copied from
55 // daemon_controller.h and must be kept in sync.
57 remoting
.HostController
.State
= {
69 remoting
.HostController
.AsyncResult
= {
77 * Checks whether or not the host plugin is valid.
79 * @return {boolean} True if the plugin is supported and loaded; false
82 remoting
.HostController
.prototype.isPluginSupported = function() {
83 return this.pluginSupported_
;
87 * @param {function(boolean, boolean, boolean):void} callback Callback to be
90 remoting
.HostController
.prototype.getConsent = function(callback
) {
91 this.plugin_
.getUsageStatsConsent(callback
);
95 * Registers and starts the host.
97 * @param {string} hostPin Host PIN.
98 * @param {boolean} consent The user's consent to crash dump reporting.
99 * @param {function(remoting.HostController.AsyncResult):void} callback
100 * callback Callback to be called when done.
101 * @return {void} Nothing.
103 remoting
.HostController
.prototype.start = function(hostPin
, consent
, callback
) {
104 /** @type {remoting.HostController} */
107 /** @return {string} */
108 function generateUuid() {
109 var random
= new Uint16Array(8);
110 window
.crypto
.getRandomValues(random
);
111 /** @type {Array.<string>} */
113 for (var i
= 0; i
< 8; i
++) {
114 e
[i
] = (/** @type {number} */random
[i
] + 0x10000).
115 toString(16).substring(1);
117 return e
[0] + e
[1] + '-' + e
[2] + "-" + e
[3] + '-' +
118 e
[4] + '-' + e
[5] + e
[6] + e
[7];
121 var newHostId
= generateUuid();
123 /** @param {function(remoting.HostController.AsyncResult):void} callback
124 * @param {remoting.HostController.AsyncResult} result
125 * @param {string} hostName
126 * @param {string} publicKey */
127 function onStarted(callback
, result
, hostName
, publicKey
) {
128 if (result
== remoting
.HostController
.AsyncResult
.OK
) {
129 remoting
.hostList
.onLocalHostStarted(hostName
, newHostId
, publicKey
);
131 // Unregister the host if we failed to start it.
132 remoting
.HostList
.unregisterHostById(newHostId
);
138 * @param {string} hostName
139 * @param {string} publicKey
140 * @param {string} privateKey
141 * @param {XMLHttpRequest} xhr
143 function onRegistered(hostName
, publicKey
, privateKey
, xhr
) {
144 var success
= (xhr
.status
== 200);
147 that
.plugin_
.getPinHash(newHostId
, hostPin
, startHostWithHash
.bind(
148 null, hostName
, publicKey
, privateKey
, xhr
));
150 console
.log('Failed to register the host. Status: ' + xhr
.status
+
151 ' response: ' + xhr
.responseText
);
152 callback(remoting
.HostController
.AsyncResult
.FAILED_DIRECTORY
);
157 * @param {string} hostName
158 * @param {string} publicKey
159 * @param {string} privateKey
160 * @param {XMLHttpRequest} xhr
161 * @param {string} hostSecretHash
163 function startHostWithHash(hostName
, publicKey
, privateKey
, xhr
,
165 var hostConfig
= JSON
.stringify({
166 xmpp_login
: remoting
.identity
.getCachedEmail(),
167 oauth_refresh_token
: remoting
.oauth2
.exportRefreshToken(),
170 host_secret_hash
: hostSecretHash
,
171 private_key
: privateKey
173 /** @param {remoting.HostController.AsyncResult} result */
174 var onStartDaemon = function(result
) {
175 onStarted(callback
, result
, hostName
, publicKey
);
177 that
.plugin_
.startDaemon(hostConfig
, consent
, onStartDaemon
);
181 * @param {string} hostName
182 * @param {string} privateKey
183 * @param {string} publicKey
184 * @param {string} oauthToken
186 function doRegisterHost(hostName
, privateKey
, publicKey
, oauthToken
) {
188 'Authorization': 'OAuth ' + oauthToken
,
189 'Content-type' : 'application/json; charset=UTF-8'
192 var newHostDetails
= { data
: {
198 remoting
.settings
.DIRECTORY_API_BASE_URL
+ '/@me/hosts/',
199 /** @param {XMLHttpRequest} xhr */
200 function (xhr
) { onRegistered(hostName
, publicKey
, privateKey
, xhr
); },
201 JSON
.stringify(newHostDetails
),
206 * @param {string} hostName
207 * @param {string} privateKey
208 * @param {string} publicKey
210 function onKeyGenerated(hostName
, privateKey
, publicKey
) {
211 remoting
.identity
.callWithToken(
212 /** @param {string} oauthToken */
213 function(oauthToken
) {
214 doRegisterHost(hostName
, privateKey
, publicKey
, oauthToken
);
216 /** @param {remoting.Error} error */
218 // TODO(jamiewalch): Have a more specific error code here?
219 callback(remoting
.HostController
.AsyncResult
.FAILED
);
224 * @param {string} hostName
225 * @return {void} Nothing.
227 function startWithHostname(hostName
) {
228 that
.plugin_
.generateKeyPair(onKeyGenerated
.bind(null, hostName
));
231 this.plugin_
.getHostName(startWithHostname
);
235 * Stop the daemon process.
236 * @param {function(remoting.HostController.AsyncResult):void} callback
237 * Callback to be called when finished.
238 * @return {void} Nothing.
240 remoting
.HostController
.prototype.stop = function(callback
) {
241 /** @type {remoting.HostController} */
245 * @param {remoting.HostController.AsyncResult} result The result of the
246 * stopDaemon call, to be passed to the callback.
247 * @param {string?} hostId The host id of the local host.
249 function unregisterHost(result
, hostId
) {
251 remoting
.HostList
.unregisterHostById(hostId
);
257 * @param {remoting.HostController.AsyncResult} result The result of the
258 * stopDaemon call, to be passed to the callback.
260 function onStopped(result
) {
261 if (result
!= remoting
.HostController
.AsyncResult
.OK
) {
265 that
.getLocalHostId(unregisterHost
.bind(null, result
));
268 this.plugin_
.stopDaemon(onStopped
);
272 * Parse a stringified host configuration and return it as a dictionary if it
273 * is well-formed and contains both host_id and xmpp_login keys. null is
274 * returned if either key is missing, or if the configuration is corrupt.
275 * @param {string} configStr The host configuration, JSON encoded to a string.
276 * @return {Object.<string,string>|null} The host configuration.
278 function parseHostConfig_(configStr
) {
279 var config
= /** @type {Object.<string,string>} */ jsonParseSafe(configStr
);
281 typeof config
['host_id'] == 'string' &&
282 typeof config
['xmpp_login'] == 'string') {
285 // {} means that host is not configured; '' means that the config file could
287 // TODO(jamiewalch): '' is expected if the host isn't installed, but should
288 // be reported as an error otherwise. Fix this once we have an event-based
289 // daemon state mechanism.
290 if (configStr
!= '{}' && configStr
!= '') {
291 console
.error('Invalid getDaemonConfig response.');
298 * @param {string} newPin The new PIN to set
299 * @param {function(remoting.HostController.AsyncResult):void} callback
300 * Callback to be called when finished.
301 * @return {void} Nothing.
303 remoting
.HostController
.prototype.updatePin = function(newPin
, callback
) {
304 /** @type {remoting.HostController} */
307 /** @param {string} configStr */
308 function onConfig(configStr
) {
309 var config
= parseHostConfig_(configStr
);
311 callback(remoting
.HostController
.AsyncResult
.FAILED
);
314 var hostId
= config
['host_id'];
315 that
.plugin_
.getPinHash(hostId
, newPin
, updateDaemonConfigWithHash
);
318 /** @param {string} pinHash */
319 function updateDaemonConfigWithHash(pinHash
) {
320 var newConfig
= JSON
.stringify({
321 host_secret_hash
: pinHash
323 that
.plugin_
.updateDaemonConfig(newConfig
, callback
);
326 // TODO(sergeyu): When crbug.com/121518 is fixed: replace this call
327 // with an upriveleged version if that is necessary.
328 this.plugin_
.getDaemonConfig(onConfig
);
332 * Get the state of the local host.
334 * @param {function(remoting.HostController.State):void} onDone
335 * Completion callback.
337 remoting
.HostController
.prototype.getLocalHostState = function(onDone
) {
338 this.plugin_
.getDaemonState(onDone
);
342 * Get the id of the local host, or null if it is not registered.
344 * @param {function(string?):void} onDone Completion callback.
346 remoting
.HostController
.prototype.getLocalHostId = function(onDone
) {
347 /** @type {remoting.HostController} */
349 /** @param {string} configStr */
350 function onConfig(configStr
) {
351 var config
= parseHostConfig_(configStr
);
354 hostId
= config
['host_id'];
359 this.plugin_
.getDaemonConfig(onConfig
);
365 /** @type {remoting.HostController} */
366 remoting
.hostController
= null;