mirror of
https://github.com/unraid/api.git
synced 2025-12-31 13:39:52 -06:00
feat: create key cli command logic and add to index command list
This commit is contained in:
117
api/src/cli/commands/key.ts
Normal file
117
api/src/cli/commands/key.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import { ArgumentConfig, parse } from 'ts-command-line-args';
|
||||||
|
|
||||||
|
import { cliLogger } from '@app/core/log';
|
||||||
|
import { Role } from '@app/graphql/generated/api/types';
|
||||||
|
import { ApiKeyService } from '@app/unraid-api/auth/api-key.service';
|
||||||
|
|
||||||
|
enum Command {
|
||||||
|
Get = 'get',
|
||||||
|
Create = 'create',
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeyFlags = {
|
||||||
|
command: string;
|
||||||
|
name: string;
|
||||||
|
create?: boolean;
|
||||||
|
roles?: string;
|
||||||
|
permissions?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validRoles: Set<Role> = new Set(Object.values(Role));
|
||||||
|
|
||||||
|
const validateRoles = (rolesStr?: string): Role[] => {
|
||||||
|
if (!rolesStr) return [Role.GUEST];
|
||||||
|
|
||||||
|
const requestedRoles = rolesStr.split(',').map((role) => role.trim().toUpperCase() as Role);
|
||||||
|
const validRequestedRoles = requestedRoles.filter((role) => validRoles.has(role));
|
||||||
|
|
||||||
|
if (validRequestedRoles.length === 0) {
|
||||||
|
throw new Error(`Invalid roles. Valid options are: ${Array.from(validRoles).join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const invalidRoles = requestedRoles.filter((role) => !validRoles.has(role));
|
||||||
|
|
||||||
|
if (invalidRoles.length > 0) {
|
||||||
|
cliLogger.warn(`Ignoring invalid roles: ${invalidRoles.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return validRequestedRoles;
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyOptions: ArgumentConfig<KeyFlags> = {
|
||||||
|
command: { type: String, description: 'get or create' },
|
||||||
|
name: { type: String, description: 'Name of the API key', typeLabel: '{underline name}' },
|
||||||
|
create: { type: Boolean, optional: true, description: "Create the key if it doesn't exist" },
|
||||||
|
roles: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
description: `Comma-separated list of roles (${Object.values(Role).join(', ')})`,
|
||||||
|
typeLabel: '{underline role1,role2}',
|
||||||
|
},
|
||||||
|
permissions: {
|
||||||
|
type: String,
|
||||||
|
optional: true,
|
||||||
|
description: 'Comma-separated list of permissions',
|
||||||
|
typeLabel: '{underline perm1,perm2}',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const key = async (...argv: string[]) => {
|
||||||
|
try {
|
||||||
|
const options = parse<KeyFlags>(keyOptions, { argv });
|
||||||
|
const apiKeyService = new ApiKeyService();
|
||||||
|
|
||||||
|
if (!options.name) {
|
||||||
|
throw new Error('Name is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (options.command) {
|
||||||
|
case Command.Create: {
|
||||||
|
const roles = validateRoles(options.roles);
|
||||||
|
const key = await apiKeyService.create(
|
||||||
|
options.name,
|
||||||
|
`CLI generated key: ${options.name}`,
|
||||||
|
roles,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('API Key: ', key);
|
||||||
|
cliLogger.info('API key created successfully');
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Command.Get: {
|
||||||
|
const key = await apiKeyService.findByField('name', options.name);
|
||||||
|
|
||||||
|
if (!key && options.create) {
|
||||||
|
const roles = validateRoles(options.roles);
|
||||||
|
const newKey = await apiKeyService.create(
|
||||||
|
options.name,
|
||||||
|
`CLI generated key: ${options.name}`,
|
||||||
|
roles,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('New API Key: ', newKey);
|
||||||
|
cliLogger.info('API key created successfully');
|
||||||
|
} else if (key) {
|
||||||
|
console.log('API Key: ', key);
|
||||||
|
} else {
|
||||||
|
throw new Error(`No API key found with name: ${options.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Invalid command. Use: ${Object.values(Command).join(' or ')}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
cliLogger.error(`Failed to process API key: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -30,6 +30,7 @@ export const main = async (...argv: string[]) => {
|
|||||||
|
|
||||||
// Only import the command we need when we use it
|
// Only import the command we need when we use it
|
||||||
const commands = {
|
const commands = {
|
||||||
|
key: import('@app/cli/commands/key').then((pkg) => pkg.key),
|
||||||
start: import('@app/cli/commands/start').then((pkg) => pkg.start),
|
start: import('@app/cli/commands/start').then((pkg) => pkg.start),
|
||||||
stop: import('@app/cli/commands/stop').then((pkg) => pkg.stop),
|
stop: import('@app/cli/commands/stop').then((pkg) => pkg.stop),
|
||||||
restart: import('@app/cli/commands/restart').then((pkg) => pkg.restart),
|
restart: import('@app/cli/commands/restart').then((pkg) => pkg.restart),
|
||||||
|
|||||||
Reference in New Issue
Block a user