Skip to content

Commit d4d9020

Browse files
committed
feat: adds create user endpoint and cli command
1 parent 6bdf166 commit d4d9020

File tree

4 files changed

+386
-0
lines changed

4 files changed

+386
-0
lines changed

packages/git-proxy-cli/index.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,59 @@ async function reloadConfig() {
330330
}
331331
}
332332

333+
/**
334+
* Create a new user
335+
* @param {string} username The username for the new user
336+
* @param {string} password The password for the new user
337+
* @param {string} email The email for the new user
338+
* @param {string} gitAccount The git account for the new user
339+
* @param {boolean} [admin=false] Whether the user should be an admin (optional)
340+
*/
341+
async function createUser(username, password, email, gitAccount, admin = false) {
342+
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
343+
console.error('Error: Create User: Authentication required');
344+
process.exitCode = 1;
345+
return;
346+
}
347+
348+
try {
349+
const cookies = JSON.parse(fs.readFileSync(GIT_PROXY_COOKIE_FILE, 'utf8'));
350+
351+
const response = await axios.post(
352+
`${baseUrl}/api/auth/create-user`,
353+
{
354+
username,
355+
password,
356+
email,
357+
gitAccount,
358+
admin,
359+
},
360+
{
361+
headers: { Cookie: cookies },
362+
},
363+
);
364+
365+
console.log(`User '${username}' created successfully`);
366+
} catch (error) {
367+
let errorMessage = `Error: Create User: '${error.message}'`;
368+
process.exitCode = 2;
369+
370+
if (error.response) {
371+
switch (error.response.status) {
372+
case 401:
373+
errorMessage = 'Error: Create User: Authentication required';
374+
process.exitCode = 3;
375+
break;
376+
case 400:
377+
errorMessage = `Error: Create User: ${error.response.data.message}`;
378+
process.exitCode = 4;
379+
break;
380+
}
381+
}
382+
console.error(errorMessage);
383+
}
384+
}
385+
333386
// Parsing command line arguments
334387
yargs(hideBin(process.argv)) // eslint-disable-line @typescript-eslint/no-unused-expressions
335388
.command({
@@ -465,6 +518,41 @@ yargs(hideBin(process.argv)) // eslint-disable-line @typescript-eslint/no-unused
465518
description: 'Reload GitProxy configuration without restarting',
466519
action: reloadConfig,
467520
})
521+
.command({
522+
command: 'create-user',
523+
describe: 'Create a new user',
524+
builder: {
525+
username: {
526+
describe: 'Username for the new user',
527+
demandOption: true,
528+
type: 'string',
529+
},
530+
password: {
531+
describe: 'Password for the new user',
532+
demandOption: true,
533+
type: 'string',
534+
},
535+
email: {
536+
describe: 'Email for the new user',
537+
demandOption: true,
538+
type: 'string',
539+
},
540+
gitAccount: {
541+
describe: 'Git account for the new user',
542+
demandOption: true,
543+
type: 'string',
544+
},
545+
admin: {
546+
describe: 'Whether the user should be an admin (optional)',
547+
demandOption: false,
548+
type: 'boolean',
549+
default: false,
550+
},
551+
},
552+
handler(argv) {
553+
createUser(argv.username, argv.password, argv.email, argv.gitAccount, argv.admin);
554+
},
555+
})
468556
.demandCommand(1, 'You need at least one command before moving on')
469557
.strict()
470558
.help().argv;

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

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,114 @@ describe('test git-proxy-cli', function () {
483483
});
484484
});
485485

486+
// *** create user ***
487+
488+
describe('test git-proxy-cli :: create-user', function () {
489+
it('attempt to create user should fail when server is down', async function () {
490+
try {
491+
// start server -> login -> stop server
492+
await helper.startServer(service);
493+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
494+
} finally {
495+
await helper.closeServer(service.httpServer);
496+
}
497+
498+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
499+
const expectedExitCode = 2;
500+
const expectedMessages = null;
501+
const expectedErrorMessages = ['Error: Create User:'];
502+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
503+
});
504+
505+
it('attempt to create user should fail when not authenticated', async function () {
506+
await helper.removeCookiesFile();
507+
508+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
509+
const expectedExitCode = 1;
510+
const expectedMessages = null;
511+
const expectedErrorMessages = ['Error: Create User: Authentication required'];
512+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
513+
});
514+
515+
it('attempt to create user should fail when not admin', async function () {
516+
try {
517+
await helper.startServer(service);
518+
await helper.runCli(
519+
`npx -- @finos/git-proxy-cli login --username testuser --password testpassword`,
520+
);
521+
522+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
523+
const expectedExitCode = 3;
524+
const expectedMessages = null;
525+
const expectedErrorMessages = ['Error: Create User: Authentication required'];
526+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
527+
} finally {
528+
await helper.closeServer(service.httpServer);
529+
}
530+
});
531+
532+
it('attempt to create user should fail with missing required fields', async function () {
533+
try {
534+
await helper.startServer(service);
535+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
536+
537+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --email [email protected] --gitAccount newgit`;
538+
const expectedExitCode = 4;
539+
const expectedMessages = null;
540+
const expectedErrorMessages = ['Error: Create User: Missing required fields'];
541+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
542+
} finally {
543+
await helper.closeServer(service.httpServer);
544+
}
545+
});
546+
547+
it('should successfully create a new user', async function () {
548+
try {
549+
await helper.startServer(service);
550+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
551+
552+
const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
553+
const expectedExitCode = 0;
554+
const expectedMessages = ["User 'newuser' created successfully"];
555+
const expectedErrorMessages = null;
556+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
557+
558+
// Verify we can login with the new user
559+
await helper.runCli(
560+
`npx -- @finos/git-proxy-cli login --username newuser --password newpass`,
561+
0,
562+
[`Login "newuser" <[email protected]>: OK`],
563+
null,
564+
);
565+
} finally {
566+
await helper.closeServer(service.httpServer);
567+
}
568+
});
569+
570+
it('should successfully create a new admin user', async function () {
571+
try {
572+
await helper.startServer(service);
573+
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
574+
575+
const cli = `npx -- @finos/git-proxy-cli create-user --username newadmin --password newpass --email [email protected] --gitAccount newgit --admin`;
576+
const expectedExitCode = 0;
577+
const expectedMessages = ["User 'newadmin' created successfully"];
578+
const expectedErrorMessages = null;
579+
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
580+
581+
// Verify we can login with the new admin user
582+
await helper.runCli(
583+
`npx -- @finos/git-proxy-cli login --username newadmin --password newpass`,
584+
0,
585+
[`Login "newadmin" <[email protected]> (admin): OK`],
586+
null,
587+
);
588+
} finally {
589+
await helper.closeServer(service.httpServer);
590+
}
591+
});
592+
});
593+
486594
// *** tests require push in db ***
487595

488596
describe('test git-proxy-cli :: git push administration', function () {

src/service/routes/auth.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,37 @@ router.get('/me', async (req, res) => {
168168
}
169169
});
170170

171+
router.post('/create-user', async (req, res) => {
172+
if (!req.user || !req.user.admin) {
173+
return res.status(401).send({
174+
message: 'You are not authorized to perform this action...',
175+
});
176+
}
177+
178+
try {
179+
const { username, password, email, gitAccount, admin: isAdmin = false } = req.body;
180+
181+
if (!username || !password || !email || !gitAccount) {
182+
return res.status(400).send({
183+
message: 'Missing required fields: username, password, email, and gitAccount are required',
184+
});
185+
}
186+
187+
await db.createUser(username, password, email, gitAccount, isAdmin);
188+
res.status(201).send({
189+
message: 'User created successfully',
190+
username,
191+
});
192+
} catch (error) {
193+
console.error('Error creating user:', error);
194+
res.status(400).send({
195+
message: error.message || 'Failed to create user',
196+
});
197+
}
198+
});
199+
200+
module.exports = router;
201+
171202
module.exports = {
172203
router,
173204
loginSuccessHandler

0 commit comments

Comments
 (0)