[Password Generation] Don't generate passwords for custom passphrase users.
[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
17  */
18 remoting.HostNativeMessaging = function() {
19   /**
20    * @type {number}
21    * @private
22    */
23   this.nextId_ = 0;
25   /**
26    * @type {Object.<number, remoting.HostNativeMessaging.PendingReply>}
27    * @private
28    */
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.
43  *
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
50  */
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).
61  *
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.
66  */
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;
80   }
83 /**
84  * @param {remoting.HostController.Feature} feature The feature to test for.
85  * @return {boolean} True if the implementation supports the named feature.
86  */
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.
96  *
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
104  */
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
120  */
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;
127   }
128   var reply = this.pendingReplies_[id];
129   if (!reply) {
130     console.error('NativeMessaging: unexpected id: ', id);
131     return;
132   }
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;
139     }
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);
146   }
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
157  */
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!';
222       }
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';
241       }
242       break;
244     default:
245       throw 'Unexpected native message: ' + message;
246   }
250  * @return {void} Nothing.
251  * @private
252  */
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);
263   }
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.
272  */
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.
288  */
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.
307  */
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.
327  */
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.
344  */
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.
354  */
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.
368  */
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.
384  */
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.
402  */
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.
415  */
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.
428  */
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.
440  */
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.
453  */
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.
469  */
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.
482  */
483 remoting.HostNativeMessaging.prototype.getCredentialsFromAuthCode =
484     function(authorizationCode, onDone, onError) {
485   this.postMessage_({
486     type: 'getCredentialsFromAuthCode',
487     authorizationCode: authorizationCode
488   }, onDone, onError);