Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / remoting / webapp / host_native_messaging.js
blobf4d2e3ccbea4c4252ebb1e1427c24845a5c917fa
1 // Copyright 2013 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 /**
6 * @fileoverview
7 * Class to communicate with the Host components via Native Messaging.
8 */
10 'use strict';
12 /** @suppress {duplicate} */
13 var remoting = remoting || {};
15 /**
16 * @constructor
18 remoting.HostNativeMessaging = function() {
19 /**
20 * @type {number}
21 * @private
23 this.nextId_ = 0;
25 /**
26 * @type {Object.<number, remoting.HostNativeMessaging.PendingReply>}
27 * @private
29 this.pendingReplies_ = {};
31 /** @type {?chrome.extension.Port} @private */
32 this.port_ = null;
34 /** @type {string} @private */
35 this.version_ = '';
37 /** @type {Array.<remoting.HostController.Feature>} @private */
38 this.supportedFeatures_ = [];
41 /**
42 * Type used for entries of |pendingReplies_| list.
44 * @param {string} type Type of the originating request.
45 * @param {function(...):void} onDone The callback, if any, to be triggered
46 * on response. The actual parameters depend on the original request type.
47 * @param {function(remoting.Error):void} onError The callback to be triggered
48 * on error.
49 * @constructor
51 remoting.HostNativeMessaging.PendingReply = function(type, onDone, onError) {
52 this.type = type;
53 this.onDone = onDone;
54 this.onError = onError;
57 /**
58 * Sets up connection to the Native Messaging host process and exchanges
59 * 'hello' messages. Invokes onDone on success and onError on failure (the
60 * native messaging host is probably not installed).
62 * @param {function(): void} onDone Called after successful initialization.
63 * @param {function(remoting.Error): void} onError Called if initialization
64 * failed.
65 * @return {void} Nothing.
67 remoting.HostNativeMessaging.prototype.initialize = function(onDone, onError) {
68 try {
69 this.port_ = chrome.runtime.connectNative(
70 'com.google.chrome.remote_desktop');
71 this.port_.onMessage.addListener(this.onIncomingMessage_.bind(this));
72 this.port_.onDisconnect.addListener(this.onDisconnect_.bind(this));
73 this.postMessage_({type: 'hello'}, onDone,
74 onError.bind(null, remoting.Error.UNEXPECTED));
75 } catch (err) {
76 console.log('Native Messaging initialization failed: ',
77 /** @type {*} */ (err));
78 onError(remoting.Error.UNEXPECTED);
79 return;
83 /**
84 * @param {remoting.HostController.Feature} feature The feature to test for.
85 * @return {boolean} True if the implementation supports the named feature.
87 remoting.HostNativeMessaging.prototype.hasFeature = function(feature) {
88 return this.supportedFeatures_.indexOf(feature) >= 0;
91 /**
92 * Attaches a new ID to the supplied message, and posts it to the Native
93 * Messaging port, adding |onDone| to the list of pending replies.
94 * |message| should have its 'type' field set, and any other fields set
95 * depending on the message type.
97 * @param {{type: string}} message The message to post.
98 * @param {function(...):void} onDone The callback, if any, to be triggered
99 * on response.
100 * @param {function(remoting.Error):void} onError The callback to be triggered
101 * on error.
102 * @return {void} Nothing.
103 * @private
105 remoting.HostNativeMessaging.prototype.postMessage_ =
106 function(message, onDone, onError) {
107 var id = this.nextId_++;
108 message['id'] = id;
109 this.pendingReplies_[id] = new remoting.HostNativeMessaging.PendingReply(
110 message.type + 'Response', onDone, onError);
111 this.port_.postMessage(message);
115 * Handler for incoming Native Messages.
117 * @param {Object} message The received message.
118 * @return {void} Nothing.
119 * @private
121 remoting.HostNativeMessaging.prototype.onIncomingMessage_ = function(message) {
122 /** @type {number} */
123 var id = message['id'];
124 if (typeof(id) != 'number') {
125 console.error('NativeMessaging: missing or non-numeric id');
126 return;
128 var reply = this.pendingReplies_[id];
129 if (!reply) {
130 console.error('NativeMessaging: unexpected id: ', id);
131 return;
133 delete this.pendingReplies_[id];
135 try {
136 var type = getStringAttr(message, 'type');
137 if (type != reply.type) {
138 throw 'Expected reply type: ' + reply.type + ', got: ' + type;
141 this.handleIncomingMessage_(message, reply.onDone);
142 } catch (e) {
143 console.error('Error while processing native message' +
144 /** @type {*} */ (e));
145 reply.onError(remoting.Error.UNEXPECTED);
150 * Handler for incoming Native Messages.
152 * @param {Object} message The received message.
153 * @param {function(...):void} onDone Function to call when we're done
154 * processing the message.
155 * @return {void} Nothing.
156 * @private
158 remoting.HostNativeMessaging.prototype.handleIncomingMessage_ =
159 function(message, onDone) {
160 var type = getStringAttr(message, 'type');
162 switch (type) {
163 case 'helloResponse':
164 this.version_ = getStringAttr(message, 'version');
165 // Old versions of the native messaging host do not return this list.
166 // Those versions default to the empty list of supported features.
167 this.supportedFeatures_ = getArrayAttr(message, 'supportedFeatures', []);
168 onDone();
169 break;
171 case 'getHostNameResponse':
172 onDone(getStringAttr(message, 'hostname'));
173 break;
175 case 'getPinHashResponse':
176 onDone(getStringAttr(message, 'hash'));
177 break;
179 case 'generateKeyPairResponse':
180 var privateKey = getStringAttr(message, 'privateKey');
181 var publicKey = getStringAttr(message, 'publicKey');
182 onDone(privateKey, publicKey);
183 break;
185 case 'updateDaemonConfigResponse':
186 var result = remoting.HostController.AsyncResult.fromString(
187 getStringAttr(message, 'result'));
188 onDone(result);
189 break;
191 case 'getDaemonConfigResponse':
192 onDone(getObjectAttr(message, 'config'));
193 break;
195 case 'getUsageStatsConsentResponse':
196 var supported = getBooleanAttr(message, 'supported');
197 var allowed = getBooleanAttr(message, 'allowed');
198 var setByPolicy = getBooleanAttr(message, 'setByPolicy');
199 onDone(supported, allowed, setByPolicy);
200 break;
202 case 'startDaemonResponse':
203 case 'stopDaemonResponse':
204 var result = remoting.HostController.AsyncResult.fromString(
205 getStringAttr(message, 'result'));
206 onDone(result);
207 break;
209 case 'getDaemonStateResponse':
210 var state = remoting.HostController.State.fromString(
211 getStringAttr(message, 'state'));
212 onDone(state);
213 break;
215 case 'getPairedClientsResponse':
216 var pairedClients = remoting.PairedClient.convertToPairedClientArray(
217 message['pairedClients']);
218 if (pairedClients != null) {
219 onDone(pairedClients);
220 } else {
221 throw 'No paired clients!';
223 break;
225 case 'clearPairedClientsResponse':
226 case 'deletePairedClientResponse':
227 onDone(getBooleanAttr(message, 'result'));
228 break;
230 case 'getHostClientIdResponse':
231 onDone(getStringAttr(message, 'clientId'));
232 break;
234 case 'getCredentialsFromAuthCodeResponse':
235 var userEmail = getStringAttr(message, 'userEmail');
236 var refreshToken = getStringAttr(message, 'refreshToken');
237 if (userEmail && refreshToken) {
238 onDone(userEmail, refreshToken);
239 } else {
240 throw 'Missing userEmail or refreshToken';
242 break;
244 default:
245 throw 'Unexpected native message: ' + message;
250 * @return {void} Nothing.
251 * @private
253 remoting.HostNativeMessaging.prototype.onDisconnect_ = function() {
254 console.error('Native Message port disconnected');
256 // Notify the error-handlers of any requests that are still outstanding.
257 var pendingReplies = this.pendingReplies_;
258 this.pendingReplies_ = {};
260 for (var id in pendingReplies) {
261 pendingReplies[/** @type {number} */(id)].onError(
262 remoting.Error.UNEXPECTED);
267 * @param {function(string):void} onDone Callback to be called with the
268 * local hostname.
269 * @param {function(remoting.Error):void} onError The callback to be triggered
270 * on error.
271 * @return {void} Nothing.
273 remoting.HostNativeMessaging.prototype.getHostName =
274 function(onDone, onError) {
275 this.postMessage_({type: 'getHostName'}, onDone, onError);
279 * Calculates PIN hash value to be stored in the config, passing the resulting
280 * hash value base64-encoded to the callback.
282 * @param {string} hostId The host ID.
283 * @param {string} pin The PIN.
284 * @param {function(string):void} onDone Callback.
285 * @param {function(remoting.Error):void} onError The callback to be triggered
286 * on error.
287 * @return {void} Nothing.
289 remoting.HostNativeMessaging.prototype.getPinHash =
290 function(hostId, pin, onDone, onError) {
291 this.postMessage_({
292 type: 'getPinHash',
293 hostId: hostId,
294 pin: pin
295 }, onDone, onError);
299 * Generates new key pair to use for the host. The specified callback is called
300 * when the key is generated. The key is returned in format understood by the
301 * host (PublicKeyInfo structure encoded with ASN.1 DER, and then BASE64).
303 * @param {function(string, string):void} onDone Callback.
304 * @param {function(remoting.Error):void} onError The callback to be triggered
305 * on error.
306 * @return {void} Nothing.
308 remoting.HostNativeMessaging.prototype.generateKeyPair =
309 function(onDone, onError) {
310 this.postMessage_({type: 'generateKeyPair'}, onDone, onError);
314 * Updates host config with the values specified in |config|. All
315 * fields that are not specified in |config| remain
316 * unchanged. Following parameters cannot be changed using this
317 * function: host_id, xmpp_login. Error is returned if |config|
318 * includes these parameters. Changes take effect before the callback
319 * is called.
321 * @param {Object} config The new config parameters.
322 * @param {function(remoting.HostController.AsyncResult):void} onDone
323 * Callback to be called when finished.
324 * @param {function(remoting.Error):void} onError The callback to be triggered
325 * on error.
326 * @return {void} Nothing.
328 remoting.HostNativeMessaging.prototype.updateDaemonConfig =
329 function(config, onDone, onError) {
330 this.postMessage_({
331 type: 'updateDaemonConfig',
332 config: config
333 }, onDone, onError);
337 * Loads daemon config. The config is passed as a JSON formatted string to the
338 * callback.
340 * @param {function(Object):void} onDone Callback.
341 * @param {function(remoting.Error):void} onError The callback to be triggered
342 * on error.
343 * @return {void} Nothing.
345 remoting.HostNativeMessaging.prototype.getDaemonConfig =
346 function(onDone, onError) {
347 this.postMessage_({type: 'getDaemonConfig'}, onDone, onError);
351 * Retrieves daemon version. The version is returned as a dotted decimal string
352 * of the form major.minor.build.patch.
353 * @return {string} The daemon version, or the empty string if not available.
355 remoting.HostNativeMessaging.prototype.getDaemonVersion = function() {
356 // Return the cached version from the 'hello' exchange.
357 return this.version_;
361 * Get the user's consent to crash reporting. The consent flags are passed to
362 * the callback as booleans: supported, allowed, set-by-policy.
364 * @param {function(boolean, boolean, boolean):void} onDone Callback.
365 * @param {function(remoting.Error):void} onError The callback to be triggered
366 * on error.
367 * @return {void} Nothing.
369 remoting.HostNativeMessaging.prototype.getUsageStatsConsent =
370 function(onDone, onError) {
371 this.postMessage_({type: 'getUsageStatsConsent'}, onDone, onError);
375 * Starts the daemon process with the specified configuration.
377 * @param {Object} config Host configuration.
378 * @param {boolean} consent Consent to report crash dumps.
379 * @param {function(remoting.HostController.AsyncResult):void} onDone
380 * Callback.
381 * @param {function(remoting.Error):void} onError The callback to be triggered
382 * on error.
383 * @return {void} Nothing.
385 remoting.HostNativeMessaging.prototype.startDaemon =
386 function(config, consent, onDone, onError) {
387 this.postMessage_({
388 type: 'startDaemon',
389 config: config,
390 consent: consent
391 }, onDone, onError);
395 * Stops the daemon process.
397 * @param {function(remoting.HostController.AsyncResult):void} onDone
398 * Callback.
399 * @param {function(remoting.Error):void} onError The callback to be triggered
400 * on error.
401 * @return {void} Nothing.
403 remoting.HostNativeMessaging.prototype.stopDaemon =
404 function(onDone, onError) {
405 this.postMessage_({type: 'stopDaemon'}, onDone, onError);
409 * Gets the installed/running state of the Host process.
411 * @param {function(remoting.HostController.State):void} onDone Callback.
412 * @param {function(remoting.Error):void} onError The callback to be triggered
413 * on error.
414 * @return {void} Nothing.
416 remoting.HostNativeMessaging.prototype.getDaemonState =
417 function(onDone, onError) {
418 this.postMessage_({type: 'getDaemonState'}, onDone, onError);
422 * Retrieves the list of paired clients.
424 * @param {function(Array.<remoting.PairedClient>):void} onDone Callback to be
425 * called with the result.
426 * @param {function(remoting.Error):void} onError Callback to be triggered
427 * on error.
429 remoting.HostNativeMessaging.prototype.getPairedClients =
430 function(onDone, onError) {
431 this.postMessage_({type: 'getPairedClients'}, onDone, onError);
435 * Clears all paired clients from the registry.
437 * @param {function(boolean):void} onDone Callback to be called when finished.
438 * @param {function(remoting.Error):void} onError Callback to be triggered
439 * on error.
441 remoting.HostNativeMessaging.prototype.clearPairedClients =
442 function(onDone, onError) {
443 this.postMessage_({type: 'clearPairedClients'}, onDone, onError);
447 * Deletes a paired client referenced by client id.
449 * @param {string} client Client to delete.
450 * @param {function(boolean):void} onDone Callback to be called when finished.
451 * @param {function(remoting.Error):void} onError Callback to be triggered
452 * on error.
454 remoting.HostNativeMessaging.prototype.deletePairedClient =
455 function(client, onDone, onError) {
456 this.postMessage_({
457 type: 'deletePairedClient',
458 clientId: client
459 }, onDone, onError);
463 * Gets the API keys to obtain/use service account credentials.
465 * @param {function(string):void} onDone Callback.
466 * @param {function(remoting.Error):void} onError The callback to be triggered
467 * on error.
468 * @return {void} Nothing.
470 remoting.HostNativeMessaging.prototype.getHostClientId =
471 function(onDone, onError) {
472 this.postMessage_({type: 'getHostClientId'}, onDone, onError);
477 * @param {string} authorizationCode OAuth authorization code.
478 * @param {function(string, string):void} onDone Callback.
479 * @param {function(remoting.Error):void} onError The callback to be triggered
480 * on error.
481 * @return {void} Nothing.
483 remoting.HostNativeMessaging.prototype.getCredentialsFromAuthCode =
484 function(authorizationCode, onDone, onError) {
485 this.postMessage_({
486 type: 'getCredentialsFromAuthCode',
487 authorizationCode: authorizationCode
488 }, onDone, onError);