From a8eed9c26ec0b509ab09f40fc6f072a91116b7dc Mon Sep 17 00:00:00 2001 From: johnnyman727 Date: Fri, 13 Nov 2015 19:16:17 -0800 Subject: [PATCH] only set key if requested --- lib/controller.js | 451 ++++++++++++++++++++-------------------- lib/tessel/provision.js | 4 +- test/unit/controller.js | 2 - test/unit/provision.js | 14 +- test/unit/tessel.js | 6 - 5 files changed, 240 insertions(+), 237 deletions(-) diff --git a/lib/controller.js b/lib/controller.js index f16f7c95..4fe9fd4d 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -18,253 +18,262 @@ var responses = { }; Tessel.list = function(opts) { - // Set the default SSK key path before we search - return provision.setDefaultKey(opts.key) - .then(function() { + var keyPromise = Promise.resolve(); + if (opts.key) { + // Set the default SSK key path before we search + keyPromise = provision.setDefaultKey(opts.key); + } - return new Promise(function(resolve, reject) { + return keyPromise.then(function() { - // Grab all attached Tessels - logs.info('Searching for nearby Tessels...'); + return new Promise(function(resolve, reject) { - // Keep a list of all the Tessels we discovered - var foundTessels = []; + // Grab all attached Tessels + logs.info('Searching for nearby Tessels...'); - // Options for Tessel discovery - var seekerOpts = { - timeout: opts.timeout * 1000, - usb: opts.usb, - lan: opts.lan, - authorized: undefined - }; + // Keep a list of all the Tessels we discovered + var foundTessels = []; - // Start looking for Tessels - var seeker = new discover.TesselSeeker().start(seekerOpts); - var noTessels = opts.authorized ? - responses.noAuth : - responses.auth; + // Options for Tessel discovery + var seekerOpts = { + timeout: opts.timeout * 1000, + usb: opts.usb, + lan: opts.lan, + authorized: undefined + }; - // When a Tessel is found - seeker.on('tessel', function displayResults(tessel) { + // Start looking for Tessels + var seeker = new discover.TesselSeeker().start(seekerOpts); + var noTessels = opts.authorized ? + responses.noAuth : + responses.auth; - var note = ''; + // When a Tessel is found + seeker.on('tessel', function displayResults(tessel) { - // Add it to our array - foundTessels.push(tessel); + var note = ''; - // Add a note if the user isn't authorized to use it yet - if (tessel.connection.connectionType === 'LAN' && !tessel.connection.authorized) { - note = '(USB connect and run `t2 provision` to authorize)'; - } + // Add it to our array + foundTessels.push(tessel); - // Print out details... - logs.basic(sprintf('\t%s\t%s\t%s', tessel.name, tessel.connection.connectionType, note)); - }); + // Add a note if the user isn't authorized to use it yet + if (tessel.connection.connectionType === 'LAN' && !tessel.connection.authorized) { + note = '(USB connect and run `t2 provision` to authorize)'; + } - // Called after CTRL+C or timeout - seeker.once('end', function stopSearch() { - // If there were no Tessels found - if (foundTessels.length === 0) { - // Report the sadness - return reject(noTessels); - } else if (foundTessels.length === 1) { - // Close all opened connections and resolve - controller.closeTesselConnections(foundTessels) - .then(resolve); - } - // If we have only one Tessel or two Tessels with the same name (just USB and LAN) - else if (foundTessels.length === 1 || - (foundTessels.length === 2 && foundTessels[0].name === foundTessels[1].name)) { - // Close all opened connections and resolve - controller.closeTesselConnections(foundTessels) - .then(resolve); - } - // Otherwise - else { - logs.info('Multiple Tessels found.'); - // Figure out which Tessel will be selected - return controller.runHeuristics(opts, foundTessels) - .then(function logSelected(tessel) { - // Report that selected Tessel to the user - logs.info('Will default to %s.', tessel.name); - }) - .catch(function(err) { - if (!(err instanceof controller.HeuristicAmbiguityError)) { - return controller.closeTesselConnections(foundTessels) - .then(reject.bind(this, err)); - } - }) - .then(function() { - // Helpful instructions on how to switch - logs.info('Set default Tessel with environment variable (e.g. "export TESSEL=bulbasaur") or use the --name flag.'); - // Close all opened connections and resolve - controller.closeTesselConnections(foundTessels) - .then(resolve); - }); - } - }); + // Print out details... + logs.basic(sprintf('\t%s\t%s\t%s', tessel.name, tessel.connection.connectionType, note)); + }); - // Stop the search if CTRL+C is hit - process.once('SIGINT', function() { - // If the seeker exists (it should) - if (seeker !== undefined) { - // Stop looking for more Tessels - seeker.stop(); - } - }); + // Called after CTRL+C or timeout + seeker.once('end', function stopSearch() { + // If there were no Tessels found + if (foundTessels.length === 0) { + // Report the sadness + return reject(noTessels); + } else if (foundTessels.length === 1) { + // Close all opened connections and resolve + controller.closeTesselConnections(foundTessels) + .then(resolve); + } + // If we have only one Tessel or two Tessels with the same name (just USB and LAN) + else if (foundTessels.length === 1 || + (foundTessels.length === 2 && foundTessels[0].name === foundTessels[1].name)) { + // Close all opened connections and resolve + controller.closeTesselConnections(foundTessels) + .then(resolve); + } + // Otherwise + else { + logs.info('Multiple Tessels found.'); + // Figure out which Tessel will be selected + return controller.runHeuristics(opts, foundTessels) + .then(function logSelected(tessel) { + // Report that selected Tessel to the user + logs.info('Will default to %s.', tessel.name); + }) + .catch(function(err) { + if (!(err instanceof controller.HeuristicAmbiguityError)) { + return controller.closeTesselConnections(foundTessels) + .then(reject.bind(this, err)); + } + }) + .then(function() { + // Helpful instructions on how to switch + logs.info('Set default Tessel with environment variable (e.g. "export TESSEL=bulbasaur") or use the --name flag.'); + // Close all opened connections and resolve + controller.closeTesselConnections(foundTessels) + .then(resolve); + }); + } + }); + + // Stop the search if CTRL+C is hit + process.once('SIGINT', function() { + // If the seeker exists (it should) + if (seeker !== undefined) { + // Stop looking for more Tessels + seeker.stop(); + } }); }); + }); }; Tessel.get = function(opts) { + + var keyPromise = Promise.resolve(); + if (opts.key) { + // Set the default SSK key path before we search + keyPromise = provision.setDefaultKey(opts.key); + } // Set the default SSK key path before we search - return provision.setDefaultKey(opts.key) - .then(function() { - return new Promise(function(resolve, reject) { - logs.info('Looking for your Tessel...'); - // Collection variable as more Tessels are found - var tessels = []; - - // Store the amount of time to look for Tessel in seconds - var seekerOpts = { - timeout: (opts.timeout || 2) * 1000, - usb: opts.usb, - lan: opts.lan, - authorized: true - }; - - if (opts.authorized !== undefined) { - seekerOpts.authorized = opts.authorized; - } + return keyPromise.then(function() { + return new Promise(function(resolve, reject) { + logs.info('Looking for your Tessel...'); + // Collection variable as more Tessels are found + var tessels = []; + + // Store the amount of time to look for Tessel in seconds + var seekerOpts = { + timeout: (opts.timeout || 2) * 1000, + usb: opts.usb, + lan: opts.lan, + authorized: true + }; - // Create a seeker object and start detecting any Tessels - var seeker = new discover.TesselSeeker().start(seekerOpts); - var noTessels = opts.authorized ? - responses.noAuth : - responses.auth; - - function searchComplete() { - // If we found no Tessels - if (tessels.length === 0) { - // Report it - return reject(noTessels); - } - // The name match for a given Tessel happens upon discovery, not at - // the completion of discovery. So if we got to this point, no Tessel - // was found with that name - else if (opts.name !== undefined) { - return reject('No Tessel found by the name ' + opts.name); - } - // If there was only one Tessel - else if (tessels.length === 1) { - // Return it immediately - logAndFinish(tessels[0]); - } - // Otherwise - else { - // Combine the same Tessels into one object - return controller.reconcileTessels(tessels) - .then(function(reconciledTessels) { - tessels = reconciledTessels; - // Run the heuristics to pick which Tessel to use - return controller.runHeuristics(opts, tessels) - .then(function finalSection(tessel) { - return logAndFinish(tessel); - }) - .catch(function(err) { - if (err instanceof controller.HeuristicAmbiguityError) { - var map = {}; - - // Open up an interactive menu for the user to choose - return controller.menu({ - prefix: colors.grey('INFO '), - prompt: { - name: 'selected', - type: 'list', - message: 'Which Tessel do want to use?', - choices: tessels.map(function(tessel, i) { - var isLAN = !!tessel.lanConnection; - var isAuthorized = isLAN && tessel.lanConnection.authorized; - var authorization = isAuthorized ? '' : '(not authorized)'; - var display = sprintf( - '\t%s\t%s\t%s', - tessel.name, - tessel.connection.connectionType, - authorization - ); - - // Map displayed name to tessel index - map[display] = i; - - return display; - }) - }, - translate: function(answer) { - return tessels[map[answer.selected]]; - } - }).then(function(tessel) { - if (!tessel) { - return controller.closeTesselConnections(tessels) - .then(function() { - return reject('No Tessel selected, mission aborted!'); - }); - } else { - // Log we found it and return it to the caller - return logAndFinish(tessel); - } - }); + if (opts.authorized !== undefined) { + seekerOpts.authorized = opts.authorized; + } - } else { - controller.closeTesselConnections(tessels) - .then(reject.bind(this, err)); - } - }); - }); - } + // Create a seeker object and start detecting any Tessels + var seeker = new discover.TesselSeeker().start(seekerOpts); + var noTessels = opts.authorized ? + responses.noAuth : + responses.auth; + + function searchComplete() { + // If we found no Tessels + if (tessels.length === 0) { + // Report it + return reject(noTessels); + } + // The name match for a given Tessel happens upon discovery, not at + // the completion of discovery. So if we got to this point, no Tessel + // was found with that name + else if (opts.name !== undefined) { + return reject('No Tessel found by the name ' + opts.name); + } + // If there was only one Tessel + else if (tessels.length === 1) { + // Return it immediately + logAndFinish(tessels[0]); } + // Otherwise + else { + // Combine the same Tessels into one object + return controller.reconcileTessels(tessels) + .then(function(reconciledTessels) { + tessels = reconciledTessels; + // Run the heuristics to pick which Tessel to use + return controller.runHeuristics(opts, tessels) + .then(function finalSection(tessel) { + return logAndFinish(tessel); + }) + .catch(function(err) { + if (err instanceof controller.HeuristicAmbiguityError) { + var map = {}; + + // Open up an interactive menu for the user to choose + return controller.menu({ + prefix: colors.grey('INFO '), + prompt: { + name: 'selected', + type: 'list', + message: 'Which Tessel do want to use?', + choices: tessels.map(function(tessel, i) { + var isLAN = !!tessel.lanConnection; + var isAuthorized = isLAN && tessel.lanConnection.authorized; + var authorization = isAuthorized ? '' : '(not authorized)'; + var display = sprintf( + '\t%s\t%s\t%s', + tessel.name, + tessel.connection.connectionType, + authorization + ); + + // Map displayed name to tessel index + map[display] = i; + + return display; + }) + }, + translate: function(answer) { + return tessels[map[answer.selected]]; + } + }).then(function(tessel) { + if (!tessel) { + return controller.closeTesselConnections(tessels) + .then(function() { + return reject('No Tessel selected, mission aborted!'); + }); + } else { + // Log we found it and return it to the caller + return logAndFinish(tessel); + } + }); - // When we find Tessels - seeker.on('tessel', function(tessel) { - // Check if this name matches the provided option (if any) - // This speeds up development by immediately ending the search - if (opts.name && opts.name === tessel.name) { - // Remove this listener because we don't need to search for the Tessel - seeker.removeListener('end', searchComplete); - // Stop searching - seeker.stop(); - // Send this Tessel back to the caller - logAndFinish(tessel); - } - // Otherwise - else { - // Store this Tessel with the others - tessels.push(tessel); - } - }); + } else { + controller.closeTesselConnections(tessels) + .then(reject.bind(this, err)); + } + }); + }); + } + } - seeker.once('end', searchComplete); - - // Accesses `tessels` in closure - function logAndFinish(tessel) { - // The Tessels that we won't be using should have their connections closed - var connectionsToClose = tessels; - if (tessel) { - logs.info(sprintf('Connected to %s over %s', tessel.name, tessel.connection.connectionType)); - connectionsToClose.splice(tessels.indexOf(tessel), 1); - controller.closeTesselConnections(connectionsToClose) - .then(function() { - return resolve(tessel); - }); - } else { - logs.info('Please specify a Tessel by name [--name ]'); - controller.closeTesselConnections(connectionsToClose) - .then(function() { - return reject('Multiple possible Tessel connections found.'); - }); - } + // When we find Tessels + seeker.on('tessel', function(tessel) { + // Check if this name matches the provided option (if any) + // This speeds up development by immediately ending the search + if (opts.name && opts.name === tessel.name) { + // Remove this listener because we don't need to search for the Tessel + seeker.removeListener('end', searchComplete); + // Stop searching + seeker.stop(); + // Send this Tessel back to the caller + logAndFinish(tessel); + } + // Otherwise + else { + // Store this Tessel with the others + tessels.push(tessel); } }); + + seeker.once('end', searchComplete); + + // Accesses `tessels` in closure + function logAndFinish(tessel) { + // The Tessels that we won't be using should have their connections closed + var connectionsToClose = tessels; + if (tessel) { + logs.info(sprintf('Connected to %s over %s', tessel.name, tessel.connection.connectionType)); + connectionsToClose.splice(tessels.indexOf(tessel), 1); + controller.closeTesselConnections(connectionsToClose) + .then(function() { + return resolve(tessel); + }); + } else { + logs.info('Please specify a Tessel by name [--name ]'); + controller.closeTesselConnections(connectionsToClose) + .then(function() { + return reject('Multiple possible Tessel connections found.'); + }); + } + } }); + }); }; /* diff --git a/lib/tessel/provision.js b/lib/tessel/provision.js index 745b1fee..fee72f44 100644 --- a/lib/tessel/provision.js +++ b/lib/tessel/provision.js @@ -165,8 +165,8 @@ actions.setDefaultKey = function(keyPath) { } // If this is not being running through CI tests and the file path // requested doesn't exist we need to reject - if ((!global.IS_TEST_ENV) && (!fs.statSync(keyPath).isFile() || - !fs.statSync(keyPath + '.pub').isFile())) { + if (!fs.statSync(keyPath).isFile() || + !fs.statSync(keyPath + '.pub').isFile()) { return reject(new Error(keyPath + ' does not contain valid public and private SSH keys.')); } diff --git a/test/unit/controller.js b/test/unit/controller.js index 60db55e2..12434c93 100644 --- a/test/unit/controller.js +++ b/test/unit/controller.js @@ -387,7 +387,6 @@ exports['Tessel.list'] = { this.standardOpts = { timeout: 0.01, - key: Tessel.TESSEL_AUTH_KEY }; done(); @@ -551,7 +550,6 @@ exports['Tessel.get'] = { this.standardOpts = { timeout: 0.01, - key: Tessel.TESSEL_AUTH_KEY }; done(); diff --git a/test/unit/provision.js b/test/unit/provision.js index c2ca3169..95fb60d3 100644 --- a/test/unit/provision.js +++ b/test/unit/provision.js @@ -483,8 +483,6 @@ exports['provision.setDefaultKey'] = { tearDown: function(done) { this.sandbox.restore(); - // Added because one test sets it false for a moment - global.IS_TEST_ENV = true; done(); }, @@ -521,9 +519,6 @@ exports['provision.setDefaultKey'] = { // setDefaultKey should reject with an error if a non-existent file was provided failNoFiles: function(test) { test.expect(1); - - global.IS_TEST_ENV = false; - provision.setDefaultKey('./no_files_here') .then(function noCall() { // This test should throw an error. Fail if it didn't @@ -537,10 +532,17 @@ exports['provision.setDefaultKey'] = { successfulSetting: function(test) { test.expect(1); - var key = 'real_file_i_promise'; + + var key = path.join(__dirname, './real_file_i_promise'); + var privateKeyPath = path.join(__dirname, './real_file_i_promise'); + var publicKeyPath = path.join(__dirname, './real_file_i_promise' + '.pub'); + fs.writeFileSync(privateKeyPath, 'test_contents'); + fs.writeFileSync(publicKeyPath, 'test_contents'); provision.setDefaultKey(key) .then(function doCall() { test.equal(Tessel.TESSEL_AUTH_KEY, key); + fs.unlinkSync(privateKeyPath); + fs.unlinkSync(publicKeyPath); test.done(); }) .catch(function noCall() { diff --git a/test/unit/tessel.js b/test/unit/tessel.js index 158f3a3e..d7fa8fba 100644 --- a/test/unit/tessel.js +++ b/test/unit/tessel.js @@ -40,7 +40,6 @@ exports['Tessel (get)'] = { this.standardOpts = { timeout: 0.01, - key: Tessel.TESSEL_AUTH_KEY }; done(); @@ -80,7 +79,6 @@ exports['Tessel (get)'] = { var customOpts = { timeout: this.standardOpts.timeout, - key: this.standardOpts.key, name: 'Does_Not_Exist' }; // Try to get Tessels but return none @@ -166,7 +164,6 @@ exports['Tessel (get)'] = { var customOpts = { timeout: this.standardOpts.timeout, - key: this.standardOpts.key, name: 'a' }; @@ -361,7 +358,6 @@ exports['Tessel (get)'] = { var customOpts = { timeout: this.standardOpts.timeout, - key: this.standardOpts.key, name: 'a' }; @@ -434,7 +430,6 @@ exports['Tessel (get); filter: unauthorized'] = { this.standardOpts = { timeout: 0.01, - key: Tessel.TESSEL_AUTH_KEY }; done(); @@ -450,7 +445,6 @@ exports['Tessel (get); filter: unauthorized'] = { var customOpts = { timeout: this.standardOpts.timeout, - key: this.standardOpts.key, authorized: true };