Auto-merge for PR #487 via VersionBot

Device api keys
This commit is contained in:
resin-io-versionbot[bot] 2017-10-18 18:20:15 +00:00 committed by GitHub
commit 0b26fda89c
11 changed files with 317 additions and 52 deletions

View File

@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).
## v6.7.0 - 2017-10-18
* Added a device api key parameter to the `os configure` command. #487 [Pagan Gazzard]
* Added a `--device-api-key` option to the `config generate` command. #487 [Pagan Gazzard]
* Added a `--device-api-key` option to the `device register` command. #487 [Pagan Gazzard]
## v6.6.13 - 2017-10-18
* Fix issue where `os download` would always download prod images #689 [Tim Perry]

View File

@ -194,9 +194,14 @@ exports.reconfigure = {
exports.generate = {
signature: 'config generate',
description: 'generate a config.json file',
help: 'Use this command to generate a config.json for a device or application\n\nExamples:\n\n $ resin config generate --device 7cf02a6\n $ resin config generate --device 7cf02a6 --output config.json\n $ resin config generate --app MyApp\n $ resin config generate --app MyApp --output config.json',
help: 'Use this command to generate a config.json for a device or application\n\nExamples:\n\n $ resin config generate --device 7cf02a6\n $ resin config generate --device 7cf02a6 --device-api-key <existingDeviceKey>\n $ resin config generate --device 7cf02a6 --output config.json\n $ resin config generate --app MyApp\n $ resin config generate --app MyApp --output config.json',
options: [
commandOptions.optionalApplication, commandOptions.optionalDevice, {
signature: 'deviceApiKey',
description: 'custom device key - note that this is only supported on ResinOS 2.0.3+',
parameter: 'device-api-key',
alias: 'k'
}, {
signature: 'output',
description: 'output',
parameter: 'output',
@ -205,7 +210,7 @@ exports.generate = {
],
permission: 'user',
action: function(params, options, done) {
var Promise, _, deviceConfig, form, prettyjson, resin, writeFileAsync;
var Promise, _, deviceConfig, form, generateApplicationConfig, generateDeviceConfig, prettyjson, ref, resin, writeFileAsync;
Promise = require('bluebird');
writeFileAsync = Promise.promisify(require('fs').writeFile);
resin = require('resin-sdk-preconfigured');
@ -213,6 +218,7 @@ exports.generate = {
form = require('resin-cli-form');
deviceConfig = require('resin-device-config');
prettyjson = require('prettyjson');
ref = require('../utils/config'), generateDeviceConfig = ref.generateDeviceConfig, generateApplicationConfig = ref.generateApplicationConfig;
if ((options.device == null) && (options.application == null)) {
throw new Error('You have to pass either a device or an application.\n\nSee the help page for examples:\n\n $ resin help config generate');
}
@ -224,11 +230,13 @@ exports.generate = {
}).then(function(resource) {
return resin.models.device.getManifestBySlug(resource.device_type).get('options').then(form.run).then(function(answers) {
if (resource.uuid != null) {
return deviceConfig.getByDevice(resource.uuid, answers);
return generateDeviceConfig(resource, options.deviceApiKey, answers);
} else {
return generateApplicationConfig(resource, answers);
}
return deviceConfig.getByApplication(resource.app_name, answers);
});
}).then(function(config) {
deviceConfig.validate(config);
if (options.output != null) {
return writeFileAsync(options.output, JSON.stringify(config));
}

View File

@ -84,7 +84,7 @@ exports.supported = {
exports.register = {
signature: 'device register <application>',
description: 'register a device',
help: 'Use this command to register a device to an application.\n\nExamples:\n\n $ resin device register MyApp',
help: 'Use this command to register a device to an application.\n\nNote that device api keys are only supported on ResinOS 2.0.3+\n\nExamples:\n\n $ resin device register MyApp\n $ resin device register MyApp --uuid <uuid>\n $ resin device register MyApp --uuid <uuid> --device-api-key <existingDeviceKey>',
permission: 'user',
options: [
{
@ -92,19 +92,25 @@ exports.register = {
description: 'custom uuid',
parameter: 'uuid',
alias: 'u'
}, {
signature: 'deviceApiKey',
description: 'custom device key',
parameter: 'device-api-key',
alias: 'k'
}
],
action: function(params, options, done) {
var Promise, resin;
var Promise, ref, ref1, resin;
Promise = require('bluebird');
resin = require('resin-sdk-preconfigured');
return resin.models.application.get(params.application).then(function(application) {
return Promise["try"](function() {
return options.uuid || resin.models.device.generateUniqueKey();
}).then(function(uuid) {
console.info("Registering to " + application.app_name + ": " + uuid);
return resin.models.device.register(application.app_name, uuid);
});
return Promise.join(resin.models.application.get(params.application), (ref = options.uuid) != null ? ref : resin.models.device.generateUniqueKey(), (ref1 = options.deviceApiKey) != null ? ref1 : resin.models.device.generateUniqueKey(), function(application, uuid, deviceApiKey) {
console.info("Registering to " + application.app_name + ": " + uuid);
if (options.deviceApiKey == null) {
console.info("Using generated device api key: " + deviceApiKey);
} else {
console.info('Using provided device api key');
}
return resin.models.device.register(application.app_name, uuid, deviceApiKey);
}).get('uuid').nodeify(done);
}
};

View File

@ -188,9 +188,9 @@ exports.buildConfig = {
};
exports.configure = {
signature: 'os configure <image> <uuid>',
signature: 'os configure <image> <uuid> [deviceApiKey]',
description: 'configure an os image',
help: 'Use this command to configure a previously downloaded operating system image for the specific device.\n\nExamples:\n\n $ resin os configure ../path/rpi.img 7cf02a6',
help: 'Use this command to configure a previously downloaded operating system image for the specific device.\n\nNote that device api keys are only supported on ResinOS 2.0.3+\n\nExamples:\n\n $ resin os configure ../path/rpi.img 7cf02a6\n $ resin os configure ../path/rpi.img 7cf02a6 <existingDeviceKey>',
permission: 'user',
options: [
commandOptions.advancedConfig, {
@ -200,22 +200,27 @@ exports.configure = {
}
],
action: function(params, options, done) {
var Promise, fs, helpers, init, readFileAsync, resin;
var Promise, fs, generateDeviceConfig, helpers, init, readFileAsync, resin;
fs = require('fs');
Promise = require('bluebird');
readFileAsync = Promise.promisify(fs.readFile);
resin = require('resin-sdk-preconfigured');
init = require('resin-device-init');
helpers = require('../utils/helpers');
generateDeviceConfig = require('../utils/config').generateDeviceConfig;
console.info('Configuring operating system image');
return resin.models.device.get(params.uuid).then(function(device) {
if (options.config) {
return readFileAsync(options.config, 'utf8').then(JSON.parse);
}
return buildConfig(params.image, device.device_type, options.advanced);
}).then(function(answers) {
return init.configure(params.image, params.uuid, answers).then(helpers.osProgressHandler);
}).nodeify(done);
return Promise["try"](function() {
if (options.config) {
return readFileAsync(options.config, 'utf8').then(JSON.parse);
}
return buildConfig(params.image, device.device_type, options.advanced);
}).then(function(answers) {
return generateDeviceConfig(device, params.deviceApiKey, answers).then(function(config) {
return init.configure(params.image, device.device_type, config, answers);
});
});
}).then(helpers.osProgressHandler).nodeify(done);
}
};

99
build/utils/config.js Normal file
View File

@ -0,0 +1,99 @@
// Generated by CoffeeScript 1.12.7
/*
Copyright 2016-2017 Resin.io
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var authenticateWithApplicationKey, authenticateWithDeviceKey;
exports.generateBaseConfig = function(application, options) {
var Promise, deviceConfig, resin;
Promise = require('bluebird');
deviceConfig = require('resin-device-config');
resin = require('resin-sdk-preconfigured');
return Promise.props({
userId: resin.auth.getUserId(),
username: resin.auth.whoami(),
apiUrl: resin.settings.get('apiUrl'),
vpnUrl: resin.settings.get('vpnUrl'),
registryUrl: resin.settings.get('registryUrl'),
deltaUrl: resin.settings.get('deltaUrl'),
pubNubKeys: resin.models.config.getPubNubKeys(),
mixpanelToken: resin.models.config.getMixpanelToken()
}).then(function(results) {
return deviceConfig.generate({
application: application,
user: {
id: results.userId,
username: results.username
},
endpoints: {
api: results.apiUrl,
vpn: results.vpnUrl,
registry: results.registryUrl,
delta: results.deltaUrl
},
pubnub: results.pubNubKeys,
mixpanel: {
token: results.mixpanelToken
}
});
});
};
exports.generateApplicationConfig = function(application, options) {
return exports.generateBaseConfig(application).tap(function(config) {
return authenticateWithApplicationKey(config, application.id);
});
};
exports.generateDeviceConfig = function(device, deviceApiKey, options) {
var resin;
resin = require('resin-sdk-preconfigured');
return resin.models.application.get(device.application_name).then(function(application) {
return exports.generateBaseConfig(application, options).tap(function(config) {
if (deviceApiKey != null) {
return authenticateWithDeviceKey(config, device.uuid, deviceApiKey);
} else {
return authenticateWithApplicationKey(config, application.id);
}
});
}).then(function(config) {
config.registered_at = Math.floor(Date.now() / 1000);
config.deviceId = device.id;
config.uuid = device.uuid;
return config;
});
};
authenticateWithApplicationKey = function(config, applicationNameOrId) {
var resin;
resin = require('resin-sdk-preconfigured');
return resin.models.application.generateApiKey(applicationNameOrId).then(function(apiKey) {
config.apiKey = apiKey;
return config;
});
};
authenticateWithDeviceKey = function(config, uuid, customDeviceApiKey) {
var Promise, resin;
Promise = require('bluebird');
resin = require('resin-sdk-preconfigured');
return Promise["try"](function() {
return customDeviceApiKey || resin.models.device.generateDeviceKey(uuid);
}).then(function(deviceApiKey) {
config.deviceApiKey = deviceApiKey;
return config;
});
};

View File

@ -106,7 +106,7 @@ environment variable (in the same standard URL format).
- [os versions &#60;type&#62;](#os-versions-60-type-62-)
- [os download &#60;type&#62;](#os-download-60-type-62-)
- [os build-config &#60;image&#62; &#60;device-type&#62;](#os-build-config-60-image-62-60-device-type-62-)
- [os configure &#60;image&#62; &#60;uuid&#62;](#os-configure-60-image-62-60-uuid-62-)
- [os configure &#60;image&#62; &#60;uuid&#62; [deviceApiKey]](#os-configure-60-image-62-60-uuid-62-deviceapikey-)
- [os initialize &#60;image&#62;](#os-initialize-60-image-62-)
- Config
@ -331,9 +331,13 @@ Examples:
Use this command to register a device to an application.
Note that device api keys are only supported on ResinOS 2.0.3+
Examples:
$ resin device register MyApp
$ resin device register MyApp --uuid <uuid>
$ resin device register MyApp --uuid <uuid> --device-api-key <existingDeviceKey>
### Options
@ -341,6 +345,10 @@ Examples:
custom uuid
#### --deviceApiKey, -k &#60;device-api-key&#62;
custom device key
## device rm &#60;uuid&#62;
Use this command to remove a device from resin.io.
@ -898,13 +906,16 @@ show advanced configuration options
the path to the output JSON file
## os configure &#60;image&#62; &#60;uuid&#62;
## os configure &#60;image&#62; &#60;uuid&#62; [deviceApiKey]
Use this command to configure a previously downloaded operating system image for the specific device.
Note that device api keys are only supported on ResinOS 2.0.3+
Examples:
$ resin os configure ../path/rpi.img 7cf02a6
$ resin os configure ../path/rpi.img 7cf02a6 <existingDeviceKey>
### Options
@ -1032,6 +1043,7 @@ Use this command to generate a config.json for a device or application
Examples:
$ resin config generate --device 7cf02a6
$ resin config generate --device 7cf02a6 --device-api-key <existingDeviceKey>
$ resin config generate --device 7cf02a6 --output config.json
$ resin config generate --app MyApp
$ resin config generate --app MyApp --output config.json
@ -1046,6 +1058,10 @@ application name
device uuid
#### --deviceApiKey, -k &#60;device-api-key&#62;
custom device key - note that this is only supported on ResinOS 2.0.3+
#### --output, -o &#60;output&#62;
output

View File

@ -224,6 +224,7 @@ exports.generate =
Examples:
$ resin config generate --device 7cf02a6
$ resin config generate --device 7cf02a6 --device-api-key <existingDeviceKey>
$ resin config generate --device 7cf02a6 --output config.json
$ resin config generate --app MyApp
$ resin config generate --app MyApp --output config.json
@ -231,6 +232,12 @@ exports.generate =
options: [
commandOptions.optionalApplication
commandOptions.optionalDevice
{
signature: 'deviceApiKey'
description: 'custom device key - note that this is only supported on ResinOS 2.0.3+'
parameter: 'device-api-key'
alias: 'k'
}
{
signature: 'output'
description: 'output'
@ -247,6 +254,7 @@ exports.generate =
form = require('resin-cli-form')
deviceConfig = require('resin-device-config')
prettyjson = require('prettyjson')
{ generateDeviceConfig, generateApplicationConfig } = require('../utils/config')
if not options.device? and not options.application?
throw new Error '''
@ -263,13 +271,15 @@ exports.generate =
return resin.models.application.get(options.application)
.then (resource) ->
resin.models.device.getManifestBySlug(resource.device_type)
.get('options')
.then(form.run)
.then (answers) ->
if resource.uuid?
return deviceConfig.getByDevice(resource.uuid, answers)
return deviceConfig.getByApplication(resource.app_name, answers)
.get('options')
.then(form.run)
.then (answers) ->
if resource.uuid?
generateDeviceConfig(resource, options.deviceApiKey, answers)
else
generateApplicationConfig(resource, answers)
.then (config) ->
deviceConfig.validate(config)
if options.output?
return writeFileAsync(options.output, JSON.stringify(config))

View File

@ -131,28 +131,45 @@ exports.register =
help: '''
Use this command to register a device to an application.
Note that device api keys are only supported on ResinOS 2.0.3+
Examples:
$ resin device register MyApp
$ resin device register MyApp --uuid <uuid>
$ resin device register MyApp --uuid <uuid> --device-api-key <existingDeviceKey>
'''
permission: 'user'
options: [
signature: 'uuid'
description: 'custom uuid'
parameter: 'uuid'
alias: 'u'
{
signature: 'uuid'
description: 'custom uuid'
parameter: 'uuid'
alias: 'u'
}
{
signature: 'deviceApiKey'
description: 'custom device key'
parameter: 'device-api-key'
alias: 'k'
}
]
action: (params, options, done) ->
Promise = require('bluebird')
resin = require('resin-sdk-preconfigured')
resin.models.application.get(params.application).then (application) ->
Promise.try ->
return options.uuid or resin.models.device.generateUniqueKey()
.then (uuid) ->
Promise.join(
resin.models.application.get(params.application)
options.uuid ? resin.models.device.generateUniqueKey()
options.deviceApiKey ? resin.models.device.generateUniqueKey()
(application, uuid, deviceApiKey) ->
console.info("Registering to #{application.app_name}: #{uuid}")
return resin.models.device.register(application.app_name, uuid)
if not options.deviceApiKey?
console.info("Using generated device api key: #{deviceApiKey}")
else
console.info('Using provided device api key')
return resin.models.device.register(application.app_name, uuid, deviceApiKey)
)
.get('uuid')
.nodeify(done)

View File

@ -196,14 +196,17 @@ exports.buildConfig =
.nodeify(done)
exports.configure =
signature: 'os configure <image> <uuid>'
signature: 'os configure <image> <uuid> [deviceApiKey]'
description: 'configure an os image'
help: '''
Use this command to configure a previously downloaded operating system image for the specific device.
Note that device api keys are only supported on ResinOS 2.0.3+
Examples:
$ resin os configure ../path/rpi.img 7cf02a6
$ resin os configure ../path/rpi.img 7cf02a6 <existingDeviceKey>
'''
permission: 'user'
options: [
@ -221,15 +224,21 @@ exports.configure =
resin = require('resin-sdk-preconfigured')
init = require('resin-device-init')
helpers = require('../utils/helpers')
{ generateDeviceConfig } = require('../utils/config')
console.info('Configuring operating system image')
resin.models.device.get(params.uuid).then (device) ->
if options.config
return readFileAsync(options.config, 'utf8')
.then(JSON.parse)
return buildConfig(params.image, device.device_type, options.advanced)
.then (answers) ->
init.configure(params.image, params.uuid, answers).then(helpers.osProgressHandler)
resin.models.device.get(params.uuid)
.then (device) ->
Promise.try ->
if options.config
return readFileAsync(options.config, 'utf8')
.then(JSON.parse)
return buildConfig(params.image, device.device_type, options.advanced)
.then (answers) ->
generateDeviceConfig(device, params.deviceApiKey, answers)
.then (config) ->
init.configure(params.image, device.device_type, config, answers)
.then(helpers.osProgressHandler)
.nodeify(done)
INIT_WARNING_MESSAGE = '''

89
lib/utils/config.coffee Normal file
View File

@ -0,0 +1,89 @@
###
Copyright 2016-2017 Resin.io
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
###
exports.generateBaseConfig = (application, options) ->
Promise = require('bluebird')
deviceConfig = require('resin-device-config')
resin = require('resin-sdk-preconfigured')
Promise.props
userId: resin.auth.getUserId()
username: resin.auth.whoami()
apiUrl: resin.settings.get('apiUrl')
vpnUrl: resin.settings.get('vpnUrl')
registryUrl: resin.settings.get('registryUrl')
deltaUrl: resin.settings.get('deltaUrl')
pubNubKeys: resin.models.config.getPubNubKeys()
mixpanelToken: resin.models.config.getMixpanelToken()
.then (results) ->
deviceConfig.generate
application: application
user:
id: results.userId
username: results.username
endpoints:
api: results.apiUrl
vpn: results.vpnUrl
registry: results.registryUrl
delta: results.deltaUrl
pubnub: results.pubNubKeys
mixpanel:
token: results.mixpanelToken
exports.generateApplicationConfig = (application, options) ->
exports.generateBaseConfig(application)
.tap (config) ->
authenticateWithApplicationKey(config, application.id)
exports.generateDeviceConfig = (device, deviceApiKey, options) ->
resin = require('resin-sdk-preconfigured')
resin.models.application.get(device.application_name)
.then (application) ->
exports.generateBaseConfig(application, options)
.tap (config) ->
# Device API keys are only safe for ResinOS 2.0.3+. We could somehow obtain
# the expected version for this config and generate one when we know it's safe,
# but instead for now we fall back to app keys unless the user has explicitly opted in.
if deviceApiKey?
authenticateWithDeviceKey(config, device.uuid, deviceApiKey)
else
authenticateWithApplicationKey(config, application.id)
.then (config) ->
# Associate a device, to prevent the supervisor
# from creating another one on its own.
config.registered_at = Math.floor(Date.now() / 1000)
config.deviceId = device.id
config.uuid = device.uuid
return config
authenticateWithApplicationKey = (config, applicationNameOrId) ->
resin = require('resin-sdk-preconfigured')
resin.models.application.generateApiKey(applicationNameOrId)
.then (apiKey) ->
config.apiKey = apiKey
return config
authenticateWithDeviceKey = (config, uuid, customDeviceApiKey) ->
Promise = require('bluebird')
resin = require('resin-sdk-preconfigured')
Promise.try ->
customDeviceApiKey || resin.models.device.generateDeviceKey(uuid)
.then (deviceApiKey) ->
config.deviceApiKey = deviceApiKey
return config

View File

@ -1,6 +1,6 @@
{
"name": "resin-cli",
"version": "6.6.13",
"version": "6.7.0",
"description": "The official resin.io CLI tool",
"main": "./build/actions/index.js",
"homepage": "https://github.com/resin-io/resin-cli",
@ -80,8 +80,8 @@
"resin-cli-form": "^1.4.1",
"resin-cli-visuals": "^1.4.0",
"resin-config-json": "^1.0.0",
"resin-device-config": "^3.0.0",
"resin-device-init": "^2.2.1",
"resin-device-config": "^4.0.0",
"resin-device-init": "^4.0.0",
"resin-docker-build": "^0.4.0",
"resin-doodles": "0.0.1",
"resin-image-fs": "^2.3.0",