You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
4.1 KiB

  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2020, NextCloud, Inc.
  4. *
  5. * @author Andreas Fischer <bantu@owncloud.com>
  6. * @author Christopher Schäpers <kondou@ts.unde.re>
  7. * @author Clark Tomlinson <fallen013@gmail.com>
  8. * @author Joas Schilling <coding@schilljs.com>
  9. * @author Laurens Post <lkpost@scept.re>
  10. * @author Morris Jobke <hey@morrisjobke.de>
  11. * @author Roeland Jago Douma <roeland@famdouma.nl>
  12. * @author Sujith H <sharidasan@owncloud.com>
  13. * @author Sean Molenaar <sean@seanmolenaar.eu>
  14. *
  15. * @license AGPL-3.0
  16. *
  17. * This code is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License, version 3,
  19. * as published by the Free Software Foundation.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License, version 3,
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>
  28. *
  29. */
  30. namespace OC\Core\Command\User;
  31. use OC\Authentication\Token\IProvider;
  32. use OC\Authentication\Token\IToken;
  33. use OCP\IUserManager;
  34. use OCP\Security\ICrypto;
  35. use OCP\Security\ISecureRandom;
  36. use Symfony\Component\Console\Command\Command;
  37. use Symfony\Component\Console\Helper\QuestionHelper;
  38. use Symfony\Component\Console\Input\InputArgument;
  39. use Symfony\Component\Console\Input\InputInterface;
  40. use Symfony\Component\Console\Input\InputOption;
  41. use Symfony\Component\Console\Output\OutputInterface;
  42. use Symfony\Component\Console\Question\Question;
  43. class AddAppPassword extends Command {
  44. /** @var IUserManager */
  45. protected $userManager;
  46. /** @var IProvider */
  47. protected $tokenProvider;
  48. /** @var ISecureRandom */
  49. private $random;
  50. /** @var ICrypto */
  51. private $crypto;
  52. public function __construct(IUserManager $userManager,
  53. IProvider $tokenProvider,
  54. ISecureRandom $random,
  55. ICrypto $crypto) {
  56. $this->tokenProvider = $tokenProvider;
  57. $this->userManager = $userManager;
  58. $this->random = $random;
  59. $this->crypto = $crypto;
  60. parent::__construct();
  61. }
  62. protected function configure() {
  63. $this
  64. ->setName('user:add-app-password')
  65. ->setDescription('Add app password for the named user')
  66. ->addArgument(
  67. 'user',
  68. InputArgument::REQUIRED,
  69. 'Username to add app password for'
  70. )
  71. ->addOption(
  72. 'password-from-env',
  73. null,
  74. InputOption::VALUE_NONE,
  75. 'read password from environment variable NC_PASS/OC_PASS'
  76. )
  77. ;
  78. }
  79. protected function execute(InputInterface $input, OutputInterface $output): int {
  80. $username = $input->getArgument('user');
  81. $user = $this->userManager->get($username);
  82. if (is_null($user)) {
  83. $output->writeln('<error>User does not exist</error>');
  84. return 1;
  85. }
  86. if ($input->getOption('password-from-env')) {
  87. $password = getenv('NC_PASS') ?? getenv('OC_PASS');
  88. if (!$password) {
  89. $output->writeln('<error>--password-from-env given, but NC_PASS is empty!</error>');
  90. return 1;
  91. }
  92. } elseif ($input->isInteractive()) {
  93. /** @var QuestionHelper $helper */
  94. $helper = $this->getHelper('question');
  95. $question = new Question('Enter the user password: ');
  96. $question->setHidden(true);
  97. $password = $helper->ask($input, $output, $question);
  98. if ($password === null) {
  99. $output->writeln("<error>Password cannot be empty!</error>");
  100. return 1;
  101. }
  102. } else {
  103. $output->writeln("<error>Interactive input or --password-from-env is needed for entering a new password!</error>");
  104. return 1;
  105. }
  106. $output->writeln('<info>The password is not validated so what you provide is what gets recorded in the token</info>');
  107. $token = $this->random->generate(72, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
  108. $this->tokenProvider->generateToken(
  109. $token,
  110. $user->getUID(),
  111. $user->getDisplayName(),
  112. $password,
  113. 'cli',
  114. IToken::PERMANENT_TOKEN,
  115. IToken::DO_NOT_REMEMBER
  116. );
  117. $output->writeln('app password:');
  118. $output->writeln($token);
  119. return 0;
  120. }
  121. }