diff --git a/src/ncc/CLI/CredentialMenu.php b/src/ncc/CLI/CredentialMenu.php index a82336f..4013525 100644 --- a/src/ncc/CLI/CredentialMenu.php +++ b/src/ncc/CLI/CredentialMenu.php @@ -2,9 +2,14 @@ namespace ncc\CLI; + use Exception; use ncc\Abstracts\Scopes; - use ncc\Exceptions\AccessDeniedException; + use ncc\Managers\CredentialManager; use ncc\Objects\CliHelpSection; + use ncc\Objects\Vault\Password\AccessToken; + use ncc\Objects\Vault\Password\UsernamePassword; + use ncc\Utilities\Console; + use ncc\Utilities\Functions; use ncc\Utilities\Resolver; class CredentialMenu @@ -14,7 +19,7 @@ * * @param $args * @return void - * @throws AccessDeniedException + * @noinspection PhpNoReturnAttributeCanBeAddedInspection */ public static function start($args): void { @@ -31,18 +36,120 @@ /** * @param $args * @return void - * @throws AccessDeniedException */ public static function addCredential($args): void { $ResolvedScope = Resolver::resolveScope(); if($ResolvedScope !== Scopes::System) + Console::outError('Insufficient permissions to add credentials'); + + // Really dumb-proofing this + $name = $args['alias'] ?? $args['name'] ?? null; + $auth_type = $args['auth-type'] ?? $args['auth'] ?? null; + $username = $args['username'] ?? $args['usr'] ?? null; + $password = $args['password'] ?? $args['pwd'] ?? null; + $token = $args['token'] ?? $args['pat'] ?? $args['private-token'] ?? null; + $encrypt = $args['encrypt'] ?? $args['encrypted'] ?? null; + + if($name === null) + $name = Console::getInput('Enter a name for the entry: '); + + if($auth_type === null) + $auth_type = Console::getInput('Enter the authentication type (login or pat): '); + + if($auth_type === 'login') { - throw new AccessDeniedException('Root permissions are required to manage the vault'); + if($username === null) + $username = Console::getInput('Username: '); + + if($password === null) + $password = Console::passwordInput('Password: '); + } + elseif($auth_type === 'pat') + { + if($token === null) + $token = Console::passwordInput('Token: '); + } + else + { + Console::outError('Invalid authentication type'); } - print('end' . PHP_EOL); + if($encrypt === null) + $encrypt = Console::getBooleanInput('Encrypt entry with your password?'); + + if($name === null) + { + Console::outError('You must specify a name for the entry (alias, name)', true, 1); + return; + } + + if($auth_type === null) + { + Console::outError('You must specify an authentication type for the entry (auth-type, auth)', true, 1); + return; + } + + $encrypt = Functions::cbool($encrypt); + + switch($auth_type) + { + case 'login': + + if($username === null) + { + Console::outError('You must specify a username for the entry (username, usr)', true, 1); + return; + } + if($password === null) + { + Console::outError('You must specify a password for the entry (password, pwd)', true, 1); + return; + } + + $pass_object = new UsernamePassword(); + $pass_object->setUsername($username); + $pass_object->setPassword($password); + + break; + + case 'pat': + + if($token === null) + { + Console::outError('You must specify a token for the entry (token, pat, private-token)', true, 1); + return; + } + + $pass_object = new AccessToken(); + $pass_object->setAccessToken($token); + + break; + + default: + Console::outError('Invalid authentication type specified', true, 1); + return; + } + + $credential_manager = new CredentialManager(); + if(!$credential_manager->getVault()->addEntry($name, $pass_object, $encrypt)) + { + Console::outError('Failed to add entry, entry already exists.', true, 1); + return; + } + + try + { + $credential_manager->saveVault(); + } + catch(Exception $e) + { + Console::outException('Failed to save vault', $e, 1); + return; + } + + Console::out('Successfully added entry', true, 0); exit(0); } @@ -53,20 +160,43 @@ */ private static function displayOptions(): void { - $options = [ + Console::out('Usage: ncc vault {command} [options]'); + Console::out('Options:'); + Console::outHelpSections([ new CliHelpSection(['help'], 'Displays this help menu about the value command'), - new CliHelpSection(['add'], 'Adds a new credential to the vault'), - new CliHelpSection(['remove'], 'Adds a new credential to the vault'), - ]; + new CliHelpSection(['add'], 'Adds a new entry to the vault (See below)'), + new CliHelpSection(['remove', '--name'], 'Removes'), + ]); + Console::out((string)null); - $options_padding = \ncc\Utilities\Functions::detectParametersPadding($options) + 4; + Console::out('If you are adding a new entry, you can run the add command in interactive mode'); + Console::out('or you can specify the options below' . PHP_EOL); - print('Usage: ncc vault {command} [options]' . PHP_EOL); - print('Options:' . PHP_EOL); - foreach($options as $option) - { - print(' ' . $option->toString($options_padding) . PHP_EOL); - } - print(PHP_EOL); + Console::out('Add Options:'); + Console::outHelpSections([ + new CliHelpSection(['--name'], 'The name of the entry'), + new CliHelpSection(['--auth-type', '--auth'], 'The type of authentication (login, pat)'), + new CliHelpSection(['--encrypted', '--encrypt'], 'Whether or not to encrypt the entry', true), + ]); + + Console::out(' login authentication type options:'); + Console::outHelpSections([ + new CliHelpSection(['--username', '--usr'], 'The username for the entry'), + new CliHelpSection(['--password', '--pwd'], 'The password for the entry'), + ]); + + Console::out(' pat authentication type options:'); + Console::outHelpSections([ + new CliHelpSection(['--token', '--pat',], 'The private access token for the entry', true), + ]); + + Console::out('Authentication Types:'); + Console::out(' login'); + Console::out(' pat' . PHP_EOL); + + Console::out('Examples:'); + Console::out(' ncc vault add --alias "My Alias" --auth-type login --username "myusername" --password "mypassword" --encrypt'); + Console::out(' ncc vault add --alias "My Alias" --auth-type pat --token "mytoken"'); + Console::out(' ncc vault remove --alias "My Alias"'); } } \ No newline at end of file diff --git a/src/ncc/Utilities/Console.php b/src/ncc/Utilities/Console.php index 5b8437b..6ae82eb 100644 --- a/src/ncc/Utilities/Console.php +++ b/src/ncc/Utilities/Console.php @@ -1,12 +1,14 @@ -find('bash'); + + if($bash_path == null) + { + self::outWarning('Unable to find bash executable, cannot hide password input'); + return self::getInput($prompt); + } + + $prompt = escapeshellarg($prompt); + $random = Functions::randomString(10); + $command = "$bash_path -c 'read -s -p $prompt $random && echo \$" . $random . "'"; + $password = rtrim(shell_exec($command)); + self::out((string)null); + return $password; + } + + /** + * @param array $sections + * @return void + */ + public static function outHelpSections(array $sections): void + { + if(!ncc::cliMode()) + return; + + $padding = Functions::detectParametersPadding($sections); + + foreach($sections as $section) + Console::out(' ' . $section->toString($padding)); + } + } \ No newline at end of file diff --git a/src/ncc/Utilities/Functions.php b/src/ncc/Utilities/Functions.php index fa4096c..8bf97b4 100644 --- a/src/ncc/Utilities/Functions.php +++ b/src/ncc/Utilities/Functions.php @@ -376,6 +376,7 @@ * @throws AccessDeniedException * @throws FileNotFoundException * @throws IOException + * @noinspection PhpUnused */ public static function loadComposerJson(string $path): ComposerJson { @@ -430,6 +431,7 @@ * * @param string $property * @return mixed|null + * @noinspection PhpMissingReturnTypeInspection */ public static function getConfigurationProperty(string $property) { @@ -452,4 +454,22 @@ return Parser::parse($version)->toString(); } + + /** + * Returns a random string + * + * @param int $length + * @return string + */ + public static function randomString(int $length = 32): string + { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) + { + $randomString .= $characters[rand(0, $charactersLength - 1)]; + } + return $randomString; + } } \ No newline at end of file