Add.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Core\Command\User\AuthTokens;
  8. use OC\Authentication\Events\AppPasswordCreatedEvent;
  9. use OC\Authentication\Token\IProvider;
  10. use OC\Authentication\Token\IToken;
  11. use OCP\EventDispatcher\IEventDispatcher;
  12. use OCP\IUserManager;
  13. use OCP\Security\ISecureRandom;
  14. use Symfony\Component\Console\Command\Command;
  15. use Symfony\Component\Console\Helper\QuestionHelper;
  16. use Symfony\Component\Console\Input\InputArgument;
  17. use Symfony\Component\Console\Input\InputInterface;
  18. use Symfony\Component\Console\Input\InputOption;
  19. use Symfony\Component\Console\Output\OutputInterface;
  20. use Symfony\Component\Console\Question\Question;
  21. class Add extends Command {
  22. public function __construct(
  23. protected IUserManager $userManager,
  24. protected IProvider $tokenProvider,
  25. private ISecureRandom $random,
  26. private IEventDispatcher $eventDispatcher,
  27. ) {
  28. parent::__construct();
  29. }
  30. protected function configure() {
  31. $this
  32. ->setName('user:auth-tokens:add')
  33. ->setAliases(['user:add-app-password'])
  34. ->setDescription('Add app password for the named account')
  35. ->addArgument(
  36. 'user',
  37. InputArgument::REQUIRED,
  38. 'Login to add app password for'
  39. )
  40. ->addOption(
  41. 'password-from-env',
  42. null,
  43. InputOption::VALUE_NONE,
  44. 'Read password from environment variable NC_PASS/OC_PASS. Alternatively it will be asked for interactively or an app password without the login password will be created.'
  45. )
  46. ;
  47. }
  48. protected function execute(InputInterface $input, OutputInterface $output): int {
  49. $username = $input->getArgument('user');
  50. $password = null;
  51. $user = $this->userManager->get($username);
  52. if (is_null($user)) {
  53. $output->writeln('<error>Account does not exist</error>');
  54. return 1;
  55. }
  56. if ($input->getOption('password-from-env')) {
  57. $password = getenv('NC_PASS') ?? getenv('OC_PASS');
  58. if (!$password) {
  59. $output->writeln('<error>--password-from-env given, but NC_PASS is empty!</error>');
  60. return 1;
  61. }
  62. } elseif ($input->isInteractive()) {
  63. /** @var QuestionHelper $helper */
  64. $helper = $this->getHelper('question');
  65. $question = new Question('Enter the account password: ');
  66. $question->setHidden(true);
  67. /** @var null|string $password */
  68. $password = $helper->ask($input, $output, $question);
  69. }
  70. if ($password === null) {
  71. $output->writeln('<info>No password provided. The generated app password will therefore have limited capabilities. Any operation that requires the login password will fail.</info>');
  72. }
  73. $token = $this->random->generate(72, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
  74. $generatedToken = $this->tokenProvider->generateToken(
  75. $token,
  76. $user->getUID(),
  77. $user->getUID(),
  78. $password,
  79. 'cli',
  80. IToken::PERMANENT_TOKEN,
  81. IToken::DO_NOT_REMEMBER
  82. );
  83. $this->eventDispatcher->dispatchTyped(
  84. new AppPasswordCreatedEvent($generatedToken)
  85. );
  86. $output->writeln('app password:');
  87. $output->writeln($token);
  88. return 0;
  89. }
  90. }