diff --git a/lib/actions/app.coffee b/lib/actions/app.coffee index 48ca54fe..12f860c0 100644 --- a/lib/actions/app.coffee +++ b/lib/actions/app.coffee @@ -1,9 +1,8 @@ _ = require('lodash') async = require('async') resin = require('../resin') -authHooks = require('../hooks/auth') -exports.create = authHooks.failIfNotLoggedIn (name, program) -> +exports.create = (name, program) -> async.waterfall [ (callback) -> @@ -25,7 +24,7 @@ exports.create = authHooks.failIfNotLoggedIn (name, program) -> ], resin.errors.handle -exports.list = authHooks.failIfNotLoggedIn -> +exports.list = -> resin.models.application.getAll (error, applications) -> resin.errors.handle(error) if error? @@ -38,7 +37,7 @@ exports.list = authHooks.failIfNotLoggedIn -> return application , [ 'ID', 'Name', 'Device Type', 'Online Devices', 'All Devices' ] -exports.info = authHooks.failIfNotLoggedIn (id) -> +exports.info = (id) -> resin.models.application.get id, (error, application) -> resin.errors.handle(error) if error? @@ -48,12 +47,12 @@ exports.info = authHooks.failIfNotLoggedIn (id) -> return application , [ 'ID', 'Name', 'Device Type', 'Git Repository', 'Commit' ] -exports.restart = authHooks.failIfNotLoggedIn (id) -> +exports.restart = (id) -> resin.models.application.restart id, (error) -> resin.errors.handle(error) if error? -exports.remove = authHooks.failIfNotLoggedIn (id, program) -> +exports.remove = (id, program) -> resin.ui.patterns.remove 'application', program.parent.yes, (callback) -> resin.models.application.remove(id, callback) , resin.errors.handle diff --git a/lib/actions/auth.coffee b/lib/actions/auth.coffee index 0d31c006..90fdd3ce 100644 --- a/lib/actions/auth.coffee +++ b/lib/actions/auth.coffee @@ -1,7 +1,6 @@ open = require('open') async = require('async') resin = require('../resin') -authHooks = require('../hooks/auth') exports.login = (credentials) -> async.waterfall [ @@ -17,7 +16,7 @@ exports.login = (credentials) -> ], resin.errors.handle -exports.logout = authHooks.failIfNotLoggedIn -> +exports.logout = -> resin.auth.logout() exports.signup = -> diff --git a/lib/actions/device.coffee b/lib/actions/device.coffee index fa2f8c75..8e3bb7a8 100644 --- a/lib/actions/device.coffee +++ b/lib/actions/device.coffee @@ -1,7 +1,6 @@ resin = require('../resin') -authHooks = require('../hooks/auth') -exports.list = authHooks.failIfNotLoggedIn (applicationId) -> +exports.list = (applicationId) -> resin.models.device.getAll applicationId, (error, devices) -> resin.errors.handle(error) if error? @@ -15,11 +14,11 @@ exports.list = authHooks.failIfNotLoggedIn (applicationId) -> return device , [ 'ID', 'Name', 'Device Type', 'Is Online', 'IP Address', 'Application', 'Status', 'Last Seen' ] -exports.remove = authHooks.failIfNotLoggedIn (id, program) -> +exports.remove = (id, program) -> resin.ui.patterns.remove 'device', program.parent.yes, (callback) -> resin.models.device.remove(id, callback) , resin.errors.handle -exports.identify = authHooks.failIfNotLoggedIn (uuid) -> +exports.identify = (uuid) -> resin.models.device.identify uuid, (error) -> resin.errors.handle(error) if error? diff --git a/lib/actions/environment-variables.coffee b/lib/actions/environment-variables.coffee index c5e17ff0..f83a4c92 100644 --- a/lib/actions/environment-variables.coffee +++ b/lib/actions/environment-variables.coffee @@ -1,13 +1,12 @@ _ = require('lodash') resin = require('../resin') -authHooks = require('../hooks/auth') SYSTEM_VAR_REGEX = /^RESIN_/ isSystemVariable = (environmentVariable) -> SYSTEM_VAR_REGEX.test(environmentVariable.name) -exports.list = authHooks.failIfNotLoggedIn (program) -> +exports.list = (program) -> applicationId = program.parent?.application if not applicationId? @@ -21,7 +20,7 @@ exports.list = authHooks.failIfNotLoggedIn (program) -> resin.log.out(resin.ui.widgets.table.horizontal(environmentVariables)) -exports.remove = authHooks.failIfNotLoggedIn (id, program) -> +exports.remove = (id, program) -> resin.ui.patterns.remove 'environment variable', program.parent.yes, (callback) -> resin.models.environmentVariables.remove(id, callback) , resin.errors.handle diff --git a/lib/actions/keys.coffee b/lib/actions/keys.coffee index 534552d3..729772c8 100644 --- a/lib/actions/keys.coffee +++ b/lib/actions/keys.coffee @@ -1,9 +1,8 @@ _ = require('lodash') resin = require('../resin') -authHooks = require('../hooks/auth') helpers = require('../helpers/helpers') -exports.list = authHooks.failIfNotLoggedIn -> +exports.list = -> resin.server.get resin.config.urls.keys, (error, response, keys) -> resin.errors.handle(error) if error? resin.log.out resin.ui.widgets.table.horizontal keys, (key) -> @@ -11,7 +10,7 @@ exports.list = authHooks.failIfNotLoggedIn -> return key , [ 'ID', 'Title' ] -exports.info = authHooks.failIfNotLoggedIn (id) -> +exports.info = (id) -> id = _.parseInt(id) # TODO: We don't have a way to query a single ssh key yet. @@ -26,7 +25,7 @@ exports.info = authHooks.failIfNotLoggedIn (id) -> key.public_key = '\n' + helpers.formatLongString(key.public_key, resin.config.sshKeyWidth) resin.log.out(resin.ui.widgets.table.vertical(key, _.identity, [ 'ID', 'Title', 'Public Key' ])) -exports.remove = authHooks.failIfNotLoggedIn (id, program) -> +exports.remove = (id, program) -> resin.ui.patterns.remove 'key', program.parent.yes, (callback) -> resin.server.delete("/user/keys/#{id}", callback) , resin.errors.handle diff --git a/lib/actions/preferences.coffee b/lib/actions/preferences.coffee index 028ccf68..c1a700ae 100644 --- a/lib/actions/preferences.coffee +++ b/lib/actions/preferences.coffee @@ -1,5 +1,5 @@ open = require('open') -authHooks = require('../hooks/auth') +resin = require('../resin') -exports.preferences = authHooks.failIfNotLoggedIn -> +exports.preferences = -> open(resin.config.urls.preferences) diff --git a/lib/app.coffee b/lib/app.coffee index 869255b7..f71d26da 100644 --- a/lib/app.coffee +++ b/lib/app.coffee @@ -39,6 +39,7 @@ resin.cli.addCommand command: 'logout' description: 'logout from resin.io' action: actions.auth.logout + permission: 'user' resin.cli.addCommand command: 'signup' @@ -50,40 +51,47 @@ resin.cli.addResource name: 'app' displayName: 'application' actions: actions.app + permission: 'user' resin.cli.addCommand command: 'app:restart ' description: 'restart an application' action: actions.app.restart + permission: 'user' # ---------- Device Module ---------- resin.cli.addResource name: 'device' displayName: 'device' actions: actions.device + permission: 'user' resin.cli.addCommand command: 'device:identify ' description: 'identify a device with a UUID' action: actions.device.identify + permission: 'user' # ---------- Preferences Module ---------- resin.cli.addCommand command: 'preferences' description: 'open preferences form' action: actions.preferences.preferences + permission: 'user' # ---------- Keys Module ---------- resin.cli.addResource name: 'key' displayName: 'ssh key' actions: actions.keys + permission: 'user' # ---------- Env Module ---------- resin.cli.addResource name: 'env' displayName: 'environment variable' actions: actions.env + permission: 'user' resin.data.prefix.set resin.config.dataPrefix, (error) -> resin.errors.handle(error) if error? diff --git a/lib/hooks/auth.coffee b/lib/resin/cli/cli-permissions.coffee similarity index 58% rename from lib/hooks/auth.coffee rename to lib/resin/cli/cli-permissions.coffee index 01801d60..4917e8ad 100644 --- a/lib/hooks/auth.coffee +++ b/lib/resin/cli/cli-permissions.coffee @@ -1,10 +1,9 @@ -_ = require('lodash') -resin = require('../resin') +auth = require('../auth/auth') -exports.failIfNotLoggedIn = (fn, onError) -> +exports.user = (fn, onError) -> return -> args = arguments - resin.auth.isLoggedIn (isLoggedIn) -> + auth.isLoggedIn (isLoggedIn) -> if not isLoggedIn error = new Error('You have to log in') diff --git a/lib/hooks/auth.spec.coffee b/lib/resin/cli/cli-permissions.spec.coffee similarity index 69% rename from lib/hooks/auth.spec.coffee rename to lib/resin/cli/cli-permissions.spec.coffee index 4c61c764..57171cfa 100644 --- a/lib/hooks/auth.spec.coffee +++ b/lib/resin/cli/cli-permissions.spec.coffee @@ -2,14 +2,16 @@ _ = require('lodash') nock = require('nock') sinon = require('sinon') expect = require('chai').expect -resin = require('../resin') -authHooks = require('./auth') -johnDoeFixture = require('../../tests/fixtures/johndoe') -mock = require('../../tests/utils/mock') +data = require('../data/data') +auth = require('../auth/auth') +config = require('../config') +cliPermissions = require('./cli-permissions') +johnDoeFixture = require('../../../tests/fixtures/johndoe') +mock = require('../../../tests/utils/mock') -describe 'Auth Hooks:', -> +describe 'CLI Permissions:', -> - describe '#failIfNotLoggedIn()', -> + describe '#user()', -> before -> mock.connection.init() @@ -19,7 +21,7 @@ describe 'Auth Hooks:', -> beforeEach (done) -> mock.fs.init() - resin.data.prefix.set(resin.config.dataPrefix, done) + data.prefix.set(config.dataPrefix, done) afterEach -> mock.fs.restore() @@ -27,18 +29,18 @@ describe 'Auth Hooks:', -> describe 'if not logged in', -> beforeEach (done) -> - resin.auth.logout(done) + auth.logout(done) it 'should not call the function', (done) -> spy = sinon.spy() - authHooks.failIfNotLoggedIn(spy, _.noop)() + cliPermissions.user(spy, _.noop)() _.defer -> expect(spy).to.not.have.been.called done() it 'it should call the second function with an error', (done) -> - func = authHooks.failIfNotLoggedIn _.noop, (error) -> + func = cliPermissions.user _.noop, (error) -> expect(error).to.be.an.instanceof(Error) done() func() @@ -48,7 +50,7 @@ describe 'Auth Hooks:', -> # (auth.isLoggedIn). A try/catch works, but it still results # in the error being printed in Mocha reporter. xit 'should throw an error if no error handler function', -> - func = authHooks.failIfNotLoggedIn(_.noop) + func = cliPermissions.user(_.noop) try func() catch error @@ -57,17 +59,17 @@ describe 'Auth Hooks:', -> describe 'if logged in', -> beforeEach (done) -> - nock(resin.config.remoteUrl) + nock(config.remoteUrl) .post('/login_', johnDoeFixture.credentials) .reply(200, johnDoeFixture.token) - resin.auth.login(johnDoeFixture.credentials, done) + auth.login(johnDoeFixture.credentials, done) it 'should call the function with the correct arguments', (done) -> args = [ 1, 2, 3, 'foo', 'bar' ] spy = sinon.spy() - authHooks.failIfNotLoggedIn(spy, _.noop).apply(null, args) + cliPermissions.user(spy, _.noop).apply(null, args) _.defer -> expect(spy).to.have.been.calledWith(args...) @@ -75,7 +77,7 @@ describe 'Auth Hooks:', -> it 'should not call the second function', (done) -> spy = sinon.spy() - authHooks.failIfNotLoggedIn(_.noop, spy)() + cliPermissions.user(_.noop, spy)() _.defer -> expect(spy).to.not.have.been.called diff --git a/lib/resin/cli/cli.coffee b/lib/resin/cli/cli.coffee index 92711464..9992869c 100644 --- a/lib/resin/cli/cli.coffee +++ b/lib/resin/cli/cli.coffee @@ -3,6 +3,7 @@ program = require('commander') pluralize = require('pluralize') indefiniteArticle = require('indefinite-article') log = require('../log/log') +cliPermissions = require('./cli-permissions') exports.getArgument = (name) -> return program[name] @@ -17,11 +18,23 @@ exports.setVersion = (version) -> action: -> log.out(version) +applyPermissions = (permission, action, onError) -> + permissionFunction = cliPermissions[permission] + if not _.isFunction(permissionFunction) + throw new Error("Invalid permission #{permission}") + return permissionFunction(action, onError) + exports.addCommand = (options = {}) -> + + if options.permission? + action = applyPermissions(options.permission, options.action, options.onError) + else + action = options.action + program .command(options.command) .description(options.description) - .action(options.action) + .action(action) return program @@ -40,24 +53,28 @@ exports.addResource = (options = {}) -> command: "#{options.name}:create " description: "create #{nameArticle} #{options.displayName}" action: options.actions.create + permission: options.permission if _.isFunction(options.actions.list) exports.addCommand command: "#{pluralizedName}" description: "list all #{pluralizedDisplayName}" action: options.actions.list + permission: options.permission if _.isFunction(options.actions.info) exports.addCommand command: "#{options.name} " description: "list a single #{options.displayName}" action: options.actions.info + permission: options.permission if _.isFunction(options.actions.remove) exports.addCommand command: "#{options.name}:rm " description: "remove #{nameArticle} #{options.displayName}" action: options.actions.remove + permission: options.permission exports.parse = (argv) -> program.parse(argv)