Skip to content

Commit f43b721

Browse files
aileenacburdine
authored andcommitted
feat(doctor): use new getGhostUid util
1 parent e8e2fb4 commit f43b721

File tree

4 files changed

+64
-146
lines changed

4 files changed

+64
-146
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,52 @@
11
'use strict';
2-
const os = require('os');
3-
const execa = require('execa');
42
const path = require('path');
53
const errors = require('../../../errors');
64
const chalk = require('chalk');
75
const fs = require('fs');
6+
const ghostUser = require('../../../utils/use-ghost-user');
87

98
const taskTitle = 'Checking logged in user and directory owner';
109

11-
function checkGhostUser() {
12-
let ghostuid;
13-
let ghostgid;
14-
15-
try {
16-
ghostuid = execa.shellSync('id -u ghost').stdout;
17-
ghostgid = execa.shellSync('id -g ghost').stdout;
18-
} catch (e) {
19-
// CASE: the ghost user doesn't exist, hence can't be used
20-
return false
21-
}
22-
23-
ghostuid = parseInt(ghostuid);
24-
ghostgid = parseInt(ghostgid);
25-
26-
return {
27-
uid: ghostuid,
28-
gid: ghostgid
29-
};
30-
}
31-
3210
function loggedInUserOwner(ctx) {
3311
const uid = process.getuid();
3412
const gid = process.getgroups();
35-
const ghostStats = checkGhostUser();
3613
const dirStats = fs.lstatSync(path.join(process.cwd()));
3714
const contentDirStats = fs.lstatSync(path.join(process.cwd(), 'content'));
3815

16+
const ghostStats = ghostUser.getGhostUid();
17+
3918
// CASE 1: check if ghost user exists and if it's currently used
4019
if (ghostStats && ghostStats.uid && ghostStats.uid === uid) {
4120
// The ghost user might have been set up on the system and also used,
4221
// but only when it owns the content folder, it's an indication that it's also used
4322
// as the linux user and shall not be used as current user.
4423
if (contentDirStats.uid === ghostStats.uid) {
45-
return Promise.reject(new errors.SystemError({
24+
throw new errors.SystemError({
4625
message: 'You can\'t use Ghost with the ghost user. Please log in with your own user.',
4726
help: `${chalk.green('https://docs.ghost.org/docs/install#section-create-a-new-user')}`,
4827
task: taskTitle
49-
}));
28+
});
5029
}
5130
}
5231

5332
// CASE 2: check if the current user is the owner of the current dir
5433
if (dirStats.uid !== uid) {
5534
if (gid.indexOf(dirStats.gid) < 0) {
56-
return Promise.reject(new errors.SystemError({
35+
throw new errors.SystemError({
5736
message: `Your current user is not the owner of the Ghost directory and also not part of the same group.
5837
Please log in with the user that owns the directory or add your user to the same group.`,
5938
help: `${chalk.green('https://docs.ghost.org/docs/install#section-create-a-new-user')}`,
6039
task: taskTitle
61-
}));
40+
});
6241
}
6342
// Yup current user is not the owner, but in the same group, so just show a warning
64-
ctx.ui.log('The current user is not the owner of the Ghost directory. This might cause problems.');
43+
ctx.ui.log(`${chalk.yellow('The current user is not the owner of the Ghost directory. This might cause problems.')}`);
6544
}
66-
67-
return Promise.resolve();
6845
}
6946

7047
module.exports = {
7148
title: taskTitle,
7249
task: loggedInUserOwner,
73-
enabled: (ctx) => ctx.instance && ctx.instance.process.name !== 'local',
74-
skip: () => os.platform() !== 'linux',
50+
enabled: (ctx) => ctx.system.platform.linux,
7551
category: ['start', 'update']
7652
}

lib/utils/use-ghost-user.js

+6-14
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ const fs = require('fs');
33
const os = require('os');
44
const execa = require('execa');
55

6-
const errors = require('../errors');
7-
86
const getGhostUid = function getGhostUid() {
97
if (os.platform() !== 'linux') {
108
return false;
@@ -17,11 +15,11 @@ const getGhostUid = function getGhostUid() {
1715
ghostgid = execa.shellSync('id -g ghost').stdout;
1816
} catch (e) {
1917
// CASE: the ghost user doesn't exist, hence can't be used
20-
if (!e.message.match(/no such user/i)) {
21-
throw new errors.ProcessError(e);
22-
}
23-
24-
return false
18+
// We just return false and not doing anything with the error,
19+
// as it would either mean, that the user doesn't exist (this
20+
// is exactly what we want), or the command is not known on a
21+
// Linux system.
22+
return false;
2523
}
2624

2725
ghostuid = parseInt(ghostuid);
@@ -34,18 +32,12 @@ const getGhostUid = function getGhostUid() {
3432
}
3533

3634
const shouldUseGhostUser = function shouldUseGhostUser(contentDir) {
37-
let ghostUser;
38-
3935
if (os.platform() !== 'linux') {
4036
return false;
4137
}
4238

4339
// get the ghost uid and gid
44-
try {
45-
ghostUser = getGhostUid();
46-
} catch (e) {
47-
throw e;
48-
}
40+
const ghostUser = getGhostUid();
4941

5042
if (!ghostUser) {
5143
return false;
Original file line numberDiff line numberDiff line change
@@ -1,139 +1,115 @@
11
'use strict';
22
const expect = require('chai').expect;
33
const sinon = require('sinon');
4-
const os = require('os');
54
const fs = require('fs');
65

7-
const execa = require('execa');
86
const errors = require('../../../../../lib/errors');
7+
const ghostUser = require('../../../../../lib/utils/use-ghost-user');
98

109
const loggedInUserOwner = require('../../../../../lib/commands/doctor/checks/logged-in-user-owner');
1110

1211
describe('Unit: Doctor Checks > loggedInUserOwner', function () {
1312
const sandbox = sinon.sandbox.create();
14-
let osStub;
15-
16-
beforeEach(() => {
17-
osStub = sandbox.stub(os, 'platform').returns('linux');
18-
})
1913

2014
afterEach(() => {
2115
sandbox.restore();
2216
});
2317

2418
it('enabled works', function () {
2519
expect(loggedInUserOwner.enabled({
26-
instance: {process: {name: 'local'}}
27-
}), 'false if process name is local').to.be.false;
28-
});
29-
30-
it('skip works', function () {
31-
osStub.returns('win32');
32-
expect(loggedInUserOwner.skip(), 'true if platform is not linux').to.be.true;
33-
expect(osStub.calledOnce).to.be.true;
20+
system: {platform: {linux: false}}
21+
}), 'false if platform is not linux').to.be.false;
3422
});
3523

3624
describe('Ghost user', function () {
3725
it('rejects if user is logged in as ghost and ghost owns content folder', function () {
3826
const uidStub = sandbox.stub(process, 'getuid').returns(1002);
3927
const gidStub = sandbox.stub(process, 'getgroups').returns([30, 1002]);
40-
const execaStub = sandbox.stub(execa, 'shellSync');
28+
const ghostUserStub = sandbox.stub(ghostUser, 'getGhostUid').returns({uid: 1002, guid: 1002});
4129
const fsStub = sandbox.stub(fs, 'lstatSync');
4230

43-
execaStub.onFirstCall().returns({stdout: '1002'});
44-
execaStub.onSecondCall().returns({stdout: '1002'});
4531
fsStub.onFirstCall().returns({uid: 1000, gid: 1000});
4632
fsStub.onSecondCall().returns({uid: 1002, gid: 1002});
4733

48-
return loggedInUserOwner.task().then(() => {
34+
try {
35+
loggedInUserOwner.task()
4936
expect(false, 'error should have been thrown').to.be.true;
50-
}).catch((error) => {
37+
} catch (error) {
5138
expect(error).to.exist;
5239
expect(uidStub.calledOnce).to.be.true;
5340
expect(gidStub.calledOnce).to.be.true;
54-
expect(execaStub.calledWithExactly('id -u ghost')).to.be.true;
55-
expect(execaStub.calledWithExactly('id -g ghost')).to.be.true;
41+
expect(ghostUserStub.calledOnce).to.be.true;
5642
expect(error).to.be.an.instanceof(errors.SystemError);
5743
expect(error.message).to.match(/You can't use Ghost with the ghost user./);
58-
});
44+
}
5945
});
6046

6147
it('resolves if user is logged in as ghost but ghost doesn\'t own the content folder', function () {
6248
const uidStub = sandbox.stub(process, 'getuid').returns(1002);
6349
const gidStub = sandbox.stub(process, 'getgroups').returns([30, 1002]);
64-
const execaStub = sandbox.stub(execa, 'shellSync');
50+
const ghostUserStub = sandbox.stub(ghostUser, 'getGhostUid').returns({uid: 1002, guid: 1002});
6551
const fsStub = sandbox.stub(fs, 'lstatSync');
6652

67-
execaStub.onFirstCall().returns({stdout: '1002'});
68-
execaStub.onSecondCall().returns({stdout: '1002'});
6953
fsStub.onFirstCall().returns({uid: 1002, gid: 1002});
7054
fsStub.onSecondCall().returns({uid: 1001, gid: 1001});
7155

72-
return loggedInUserOwner.task().then(() => {
73-
expect(uidStub.calledOnce).to.be.true;
74-
expect(gidStub.calledOnce).to.be.true;
75-
expect(execaStub.calledWithExactly('id -u ghost')).to.be.true;
76-
expect(execaStub.calledWithExactly('id -g ghost')).to.be.true;
77-
});
56+
loggedInUserOwner.task();
57+
expect(uidStub.calledOnce).to.be.true;
58+
expect(gidStub.calledOnce).to.be.true;
59+
expect(ghostUserStub.calledOnce).to.be.true;
7860
});
7961
});
8062

8163
describe('Other users', function () {
8264
it('rejects if current user is not owner and not in the same group as owner', function () {
8365
const uidStub = sandbox.stub(process, 'getuid').returns(1000);
8466
const gidStub = sandbox.stub(process, 'getgroups').returns([30, 1000]);
85-
const execaStub = sandbox.stub(execa, 'shellSync');
67+
const ghostUserStub = sandbox.stub(ghostUser, 'getGhostUid').returns({uid: 1002, guid: 1002});
8668
const fsStub = sandbox.stub(fs, 'lstatSync');
8769

88-
execaStub.onFirstCall().returns({stdout: '1002'});
89-
execaStub.onSecondCall().returns({stdout: '1002'});
9070
fsStub.onFirstCall().returns({uid: 1001, gid: 1001});
9171
fsStub.onSecondCall().returns({uid: 1002, gid: 1002});
9272

93-
return loggedInUserOwner.task().then(() => {
73+
try {
74+
loggedInUserOwner.task();
9475
expect(false, 'error should have been thrown').to.be.true;
95-
}).catch((error) => {
76+
} catch (error) {
9677
expect(error).to.exist;
9778
expect(uidStub.calledOnce).to.be.true;
9879
expect(gidStub.calledOnce).to.be.true;
99-
expect(execaStub.calledWithExactly('id -u ghost')).to.be.true;
100-
expect(execaStub.calledWithExactly('id -g ghost')).to.be.true;
80+
expect(ghostUserStub.calledOnce).to.be.true;
10181
expect(error).to.be.an.instanceof(errors.SystemError);
10282
expect(error.message).to.match(/Your current user is not the owner of the Ghost directory and also not part of the same group./);
103-
});
83+
}
10484
});
10585

10686
it('shows a warning message, if user is logged in as different user than owner, but same group', function () {
10787
const uidStub = sandbox.stub(process, 'getuid').returns(1001);
10888
const gidStub = sandbox.stub(process, 'getgroups').returns([30, 1000]);
109-
const execaStub = sandbox.stub(execa, 'shellSync');
89+
const ghostUserStub = sandbox.stub(ghostUser, 'getGhostUid').returns({uid: 1002, guid: 1002});
11090
const fsStub = sandbox.stub(fs, 'lstatSync');
11191
const logStub = sandbox.stub();
11292

11393
const ctx = {
11494
ui: {log: logStub}
11595
};
11696

117-
execaStub.onFirstCall().returns({stdout: '1002'});
118-
execaStub.onSecondCall().returns({stdout: '1002'});
11997
fsStub.onFirstCall().returns({uid: 1000, gid: 1000});
12098
fsStub.onSecondCall().returns({uid: 1002, gid: 1002});
12199

122-
return loggedInUserOwner.task(ctx).then(() => {
123-
expect(uidStub.calledOnce).to.be.true;
124-
expect(gidStub.calledOnce).to.be.true;
125-
expect(logStub.calledOnce).to.be.true;
126-
expect(logStub.args[0][0]).to.match(/The current user is not the owner of the Ghost directory. This might cause problems./);
127-
expect(execaStub.calledWithExactly('id -u ghost')).to.be.true;
128-
expect(execaStub.calledWithExactly('id -g ghost')).to.be.true;
129-
});
100+
loggedInUserOwner.task(ctx);
101+
expect(uidStub.calledOnce).to.be.true;
102+
expect(gidStub.calledOnce).to.be.true;
103+
expect(logStub.calledOnce).to.be.true;
104+
expect(logStub.args[0][0]).to.match(/The current user is not the owner of the Ghost directory. This might cause problems./);
105+
expect(ghostUserStub.calledOnce).to.be.true;
130106
});
131107

132108
it('resolves if current user is also the owner', function () {
133109
const uidStub = sandbox.stub(process, 'getuid').returns(1000);
134110
const gidStub = sandbox.stub(process, 'getgroups').returns([30, 1000]);
135111
// Ghost user doesn't exist this time
136-
const execaStub = sandbox.stub(execa, 'shellSync').throws(new Error('no such user'));
112+
const ghostUserStub = sandbox.stub(ghostUser, 'getGhostUid').returns(false);
137113
const fsStub = sandbox.stub(fs, 'lstatSync');
138114
const logStub = sandbox.stub();
139115

@@ -144,12 +120,27 @@ describe('Unit: Doctor Checks > loggedInUserOwner', function () {
144120
fsStub.onFirstCall().returns({uid: 1000, gid: 1000});
145121
fsStub.onSecondCall().returns({uid: 1002, gid: 1002});
146122

147-
return loggedInUserOwner.task(ctx).then(() => {
148-
expect(uidStub.calledOnce).to.be.true;
149-
expect(gidStub.calledOnce).to.be.true;
150-
expect(logStub.calledOnce).to.be.false;
151-
expect(execaStub.calledOnce).to.be.true;
152-
});
123+
loggedInUserOwner.task(ctx);
124+
expect(uidStub.calledOnce).to.be.true;
125+
expect(gidStub.calledOnce).to.be.true;
126+
expect(logStub.calledOnce).to.be.false;
127+
expect(ghostUserStub.calledOnce).to.be.true;
128+
});
129+
130+
it('rejects and passes the error if ghostUser util throws error', function () {
131+
const uidStub = sandbox.stub(process, 'getuid').returns(1000);
132+
const gidStub = sandbox.stub(process, 'getgroups').returns([30, 1000]);
133+
// getGhostUid throws error this time
134+
const ghostUserStub = sandbox.stub(ghostUser, 'getGhostUid').returns(false);
135+
const fsStub = sandbox.stub(fs, 'lstatSync');
136+
137+
fsStub.onFirstCall().returns({uid: 1000, gid: 1000});
138+
fsStub.onSecondCall().returns({uid: 1002, gid: 1002});
139+
140+
loggedInUserOwner.task();
141+
expect(uidStub.calledOnce).to.be.true;
142+
expect(gidStub.calledOnce).to.be.true;
143+
expect(ghostUserStub.calledOnce).to.be.true;
153144
});
154145
});
155146
});

0 commit comments

Comments
 (0)