diff --git a/lib/command.js b/lib/command.js index 35771d6f0..5b891c9b3 100644 --- a/lib/command.js +++ b/lib/command.js @@ -167,6 +167,12 @@ class Command { checkValidInstall(commandName); } + if (!this.allowRoot) { + const checkRootUser = require('./utils/check-root-user'); + // Check if user is trying to install as `root` + checkRootUser(); + } + // Set process title process.title = `ghost ${commandName}`; const verbose = argv.verbose; diff --git a/lib/commands/version.js b/lib/commands/version.js index 4e0161a93..01038dc30 100644 --- a/lib/commands/version.js +++ b/lib/commands/version.js @@ -20,5 +20,6 @@ class VersionCommand extends Command { VersionCommand.description = 'Prints out Ghost-CLI version (and Ghost version if one exists)'; VersionCommand.global = true; +VersionCommand.allowRoot = true; module.exports = VersionCommand; diff --git a/lib/utils/check-root-user.js b/lib/utils/check-root-user.js new file mode 100644 index 000000000..fa5414ba2 --- /dev/null +++ b/lib/utils/check-root-user.js @@ -0,0 +1,15 @@ +'use strict'; + +const chalk = require('chalk'); + +function checkRootUser() { + if (process.getuid() === 0) { + console.error(`${chalk.yellow('Can\'t run command as \'root\' user.')} +Please create a new user with regular account privileges and use this user to run the command. +See ${chalk.underline.blue('https://docs.ghost.org/docs/install#section-create-a-new-user')} for more information`); + + process.exit(1); + } +} + +module.exports = checkRootUser; diff --git a/test/unit/command-spec.js b/test/unit/command-spec.js index d4808310d..b25d79640 100644 --- a/test/unit/command-spec.js +++ b/test/unit/command-spec.js @@ -192,6 +192,25 @@ describe('Unit: Command', function () { } }); + it('will not run command when executed as root user', function () { + const checkRootUserStub = sandbox.stub(); + const Command = proxyquire(modulePath, { + './utils/check-root-user': checkRootUserStub + }); + + const TestCommand = class extends Command {}; + TestCommand.global = true; + + checkRootUserStub.throws(); + + try { + TestCommand._run('test'); + } catch (e) { + expect(e).to.exist; + expect(checkRootUserStub.calledOnce).to.be.true; + } + }); + it('loads system and ui dependencies, calls run method', function () { const uiStub = sandbox.stub().returns({ui: true}); const setEnvironmentStub = sandbox.stub(); diff --git a/test/unit/utils/check-root-user-spec.js b/test/unit/utils/check-root-user-spec.js new file mode 100644 index 000000000..6c5824e58 --- /dev/null +++ b/test/unit/utils/check-root-user-spec.js @@ -0,0 +1,41 @@ +'use strict'; + +const expect = require('chai').expect; +const sinon = require('sinon'); +const checkRootUser = require('../../../lib/utils/check-root-user'); + +describe('checkRootUser', function () { + const sandbox = sinon.sandbox.create(); + + afterEach(() => { + sandbox.restore(); + }) + + it('throws error command run with root', function () { + const processStub = sandbox.stub(process, 'getuid').returns(0); + const exitStub = sandbox.stub(process, 'exit').throws(); + const errorStub = sandbox.stub(console, 'error'); + + try { + checkRootUser('test'); + throw new Error('should not be thrown'); + } catch (e) { + expect(e.message).to.not.equal('should not be thrown'); + expect(processStub.calledOnce).to.be.true; + expect(errorStub.calledOnce).to.be.true; + expect(exitStub.calledOnce).to.be.true; + expect(errorStub.args[0][0]).to.match(/Can't run command as 'root' user/); + } + }); + + it('doesn\'t do anything if command run as non root user', function () { + const processStub = sandbox.stub(process, 'getuid').returns(501); + const exitStub = sandbox.stub(process, 'exit').throws(); + const errorStub = sandbox.stub(console, 'error'); + + checkRootUser('test'); + expect(processStub.calledOnce).to.be.true; + expect(errorStub.calledOnce).to.be.false; + expect(exitStub.calledOnce).to.be.false; + }); +});