Skip to content

Commit 271916f

Browse files
committed
feat: adds create user endpoint and cli command
1 parent e6d7446 commit 271916f

File tree

4 files changed

+389
-9
lines changed

4 files changed

+389
-9
lines changed

packages/git-proxy-cli/index.js

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ const util = require('util');
77

88
const GIT_PROXY_COOKIE_FILE = 'git-proxy-cookie';
99
// GitProxy UI HOST and PORT (configurable via environment variable)
10-
const { GIT_PROXY_UI_HOST: uiHost = 'http://localhost', GIT_PROXY_UI_PORT: uiPort = 8080 } = process.env;
10+
const { GIT_PROXY_UI_HOST: uiHost = 'http://localhost', GIT_PROXY_UI_PORT: uiPort = 8080 } =
11+
process.env;
1112

1213
const baseUrl = `${uiHost}:${uiPort}`;
1314

@@ -306,6 +307,59 @@ async function logout() {
306307
console.log('Logout: OK');
307308
}
308309

310+
/**
311+
* Create a new user
312+
* @param {string} username The username for the new user
313+
* @param {string} password The password for the new user
314+
* @param {string} email The email for the new user
315+
* @param {string} gitAccount The git account for the new user
316+
* @param {boolean} [admin=false] Whether the user should be an admin (optional)
317+
*/
318+
async function createUser(username, password, email, gitAccount, admin = false) {
319+
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
320+
console.error('Error: Create User: Authentication required');
321+
process.exitCode = 1;
322+
return;
323+
}
324+
325+
try {
326+
const cookies = JSON.parse(fs.readFileSync(GIT_PROXY_COOKIE_FILE, 'utf8'));
327+
328+
const response = await axios.post(
329+
`${baseUrl}/api/auth/create-user`,
330+
{
331+
username,
332+
password,
333+
email,
334+
gitAccount,
335+
admin,
336+
},
337+
{
338+
headers: { Cookie: cookies },
339+
},
340+
);
341+
342+
console.log(`User '${username}' created successfully`);
343+
} catch (error) {
344+
let errorMessage = `Error: Create User: '${error.message}'`;
345+
process.exitCode = 2;
346+
347+
if (error.response) {
348+
switch (error.response.status) {
349+
case 401:
350+
errorMessage = 'Error: Create User: Authentication required';
351+
process.exitCode = 3;
352+
break;
353+
case 400:
354+
errorMessage = `Error: Create User: ${error.response.data.message}`;
355+
process.exitCode = 4;
356+
break;
357+
}
358+
}
359+
console.error(errorMessage);
360+
}
361+
}
362+
309363
// Parsing command line arguments
310364
yargs(hideBin(process.argv)) // eslint-disable-line @typescript-eslint/no-unused-expressions
311365
.command({
@@ -436,6 +490,41 @@ yargs(hideBin(process.argv)) // eslint-disable-line @typescript-eslint/no-unused
436490
rejectGitPush(argv.id);
437491
},
438492
})
493+
.command({
494+
command: 'create-user',
495+
describe: 'Create a new user',
496+
builder: {
497+
username: {
498+
describe: 'Username for the new user',
499+
demandOption: true,
500+
type: 'string',
501+
},
502+
password: {
503+
describe: 'Password for the new user',
504+
demandOption: true,
505+
type: 'string',
506+
},
507+
email: {
508+
describe: 'Email for the new user',
509+
demandOption: true,
510+
type: 'string',
511+
},
512+
gitAccount: {
513+
describe: 'Git account for the new user',
514+
demandOption: true,
515+
type: 'string',
516+
},
517+
admin: {
518+
describe: 'Whether the user should be an admin (optional)',
519+
demandOption: false,
520+
type: 'boolean',
521+
default: false,
522+
},
523+
},
524+
handler(argv) {
525+
createUser(argv.username, argv.password, argv.email, argv.gitAccount, argv.admin);
526+
},
527+
})
439528
.demandCommand(1, 'You need at least one command before moving on')
440529
.strict()
441530
.help().argv;

packages/git-proxy-cli/test/testCli.test.js

Lines changed: 108 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -620,20 +620,121 @@ describe('test git-proxy-cli', function () {
620620
it('attempt to reject should fail when git push ID not found', async function () {
621621
try {
622622
await helper.startServer(service);
623-
await helper.runCli(
624-
`npx -- @finos/git-proxy-cli login --username admin --password admin`,
625-
);
623+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
626624

627625
const id = GHOST_PUSH_ID;
628626
const cli = `npx -- @finos/git-proxy-cli reject --id ${id}`;
629627
const expectedExitCode = 4;
630628
const expectedMessages = null;
631629
const expectedErrorMessages = [`Error: Reject: ID: '${id}': Not Found`];
630+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
631+
} finally {
632+
await helper.closeServer(service.httpServer);
633+
}
634+
});
635+
});
636+
637+
// *** create user ***
638+
639+
describe('test git-proxy-cli :: create-user', function () {
640+
it('attempt to create user should fail when server is down', async function () {
641+
try {
642+
// start server -> login -> stop server
643+
await helper.startServer(service);
644+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
645+
} finally {
646+
await helper.closeServer(service.httpServer);
647+
}
648+
649+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
650+
const expectedExitCode = 2;
651+
const expectedMessages = null;
652+
const expectedErrorMessages = ['Error: Create User:'];
653+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
654+
});
655+
656+
it('attempt to create user should fail when not authenticated', async function () {
657+
await helper.removeCookiesFile();
658+
659+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
660+
const expectedExitCode = 1;
661+
const expectedMessages = null;
662+
const expectedErrorMessages = ['Error: Create User: Authentication required'];
663+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
664+
});
665+
666+
it('attempt to create user should fail when not admin', async function () {
667+
try {
668+
await helper.startServer(service);
632669
await helper.runCli(
633-
cli,
634-
expectedExitCode,
635-
expectedMessages,
636-
expectedErrorMessages,
670+
`npx -- @finos/git-proxy-cli login --username testuser --password testpassword`,
671+
);
672+
673+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
674+
const expectedExitCode = 3;
675+
const expectedMessages = null;
676+
const expectedErrorMessages = ['Error: Create User: Authentication required'];
677+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
678+
} finally {
679+
await helper.closeServer(service.httpServer);
680+
}
681+
});
682+
683+
it('attempt to create user should fail with missing required fields', async function () {
684+
try {
685+
await helper.startServer(service);
686+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
687+
688+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --email [email protected] --gitAccount newgit`;
689+
const expectedExitCode = 4;
690+
const expectedMessages = null;
691+
const expectedErrorMessages = ['Error: Create User: Missing required fields'];
692+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
693+
} finally {
694+
await helper.closeServer(service.httpServer);
695+
}
696+
});
697+
698+
it('should successfully create a new user', async function () {
699+
try {
700+
await helper.startServer(service);
701+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
702+
703+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
704+
const expectedExitCode = 0;
705+
const expectedMessages = ["User 'newuser' created successfully"];
706+
const expectedErrorMessages = null;
707+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
708+
709+
// Verify we can login with the new user
710+
await helper.runCli(
711+
`npx -- @finos/git-proxy-cli login --username newuser --password newpass`,
712+
0,
713+
[`Login "newuser" <[email protected]>: OK`],
714+
null,
715+
);
716+
} finally {
717+
await helper.closeServer(service.httpServer);
718+
}
719+
});
720+
721+
it('should successfully create a new admin user', async function () {
722+
try {
723+
await helper.startServer(service);
724+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
725+
726+
const cli = `npx -- @finos/git-proxy-cli create-user --username newadmin --password newpass --email [email protected] --gitAccount newgit --admin`;
727+
const expectedExitCode = 0;
728+
const expectedMessages = ["User 'newadmin' created successfully"];
729+
const expectedErrorMessages = null;
730+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
731+
732+
// Verify we can login with the new admin user
733+
await helper.runCli(
734+
`npx -- @finos/git-proxy-cli login --username newadmin --password newpass`,
735+
0,
736+
[`Login "newadmin" <[email protected]> (admin): OK`],
737+
null,
637738
);
638739
} finally {
639740
await helper.closeServer(service.httpServer);

src/service/routes/auth.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ const router = new express.Router();
33
const passport = require('../passport').getPassport();
44
const db = require('../../db');
55
const passportType = passport.type;
6-
const { GIT_PROXY_UI_HOST: uiHost = 'http://localhost', GIT_PROXY_UI_PORT: uiPort = 3000 } = process.env;
6+
const { GIT_PROXY_UI_HOST: uiHost = 'http://localhost', GIT_PROXY_UI_PORT: uiPort = 3000 } =
7+
process.env;
78

89
router.get('/', (req, res) => {
910
res.status(200).json({
@@ -147,4 +148,34 @@ router.get('/userLoggedIn', async (req, res) => {
147148
res.status(401).end();
148149
}
149150
});
151+
152+
router.post('/create-user', async (req, res) => {
153+
if (!req.user || !req.user.admin) {
154+
return res.status(401).send({
155+
message: 'You are not authorized to perform this action...',
156+
});
157+
}
158+
159+
try {
160+
const { username, password, email, gitAccount, admin: isAdmin = false } = req.body;
161+
162+
if (!username || !password || !email || !gitAccount) {
163+
return res.status(400).send({
164+
message: 'Missing required fields: username, password, email, and gitAccount are required',
165+
});
166+
}
167+
168+
await db.createUser(username, password, email, gitAccount, isAdmin);
169+
res.status(201).send({
170+
message: 'User created successfully',
171+
username,
172+
});
173+
} catch (error) {
174+
console.error('Error creating user:', error);
175+
res.status(400).send({
176+
message: error.message || 'Failed to create user',
177+
});
178+
}
179+
});
180+
150181
module.exports = router;

0 commit comments

Comments
 (0)