2020-11-23 17:10:48 -05:00
< ? php
2022-03-23 13:44:16 -04:00
declare ( strict_types = 1 );
2020-11-23 17:10:48 -05:00
/**
2024-05-24 13:43:47 -04:00
* SPDX - FileCopyrightText : 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX - License - Identifier : AGPL - 3.0 - or - later
2020-11-23 17:10:48 -05:00
*/
2023-08-24 10:42:30 -04:00
namespace OC\Core\Command\User\AuthTokens ;
2020-11-23 17:10:48 -05:00
2022-03-10 09:25:22 -05:00
use OC\Authentication\Events\AppPasswordCreatedEvent ;
2020-11-23 17:10:48 -05:00
use OC\Authentication\Token\IProvider ;
use OC\Authentication\Token\IToken ;
2022-03-10 09:25:22 -05:00
use OCP\EventDispatcher\IEventDispatcher ;
2020-11-23 17:10:48 -05:00
use OCP\IUserManager ;
use OCP\Security\ISecureRandom ;
use Symfony\Component\Console\Command\Command ;
use Symfony\Component\Console\Helper\QuestionHelper ;
use Symfony\Component\Console\Input\InputArgument ;
use Symfony\Component\Console\Input\InputInterface ;
use Symfony\Component\Console\Input\InputOption ;
use Symfony\Component\Console\Output\OutputInterface ;
use Symfony\Component\Console\Question\Question ;
2023-08-24 10:42:30 -04:00
class Add extends Command {
2023-06-12 10:41:17 -04:00
public function __construct (
protected IUserManager $userManager ,
protected IProvider $tokenProvider ,
private ISecureRandom $random ,
private IEventDispatcher $eventDispatcher ,
) {
2020-11-23 17:10:48 -05:00
parent :: __construct ();
}
protected function configure () {
$this
2023-08-24 10:42:30 -04:00
-> setName ( 'user:auth-tokens:add' )
-> setAliases ([ 'user:add-app-password' ])
2022-09-21 11:44:32 -04:00
-> setDescription ( 'Add app password for the named account' )
2020-11-23 17:10:48 -05:00
-> addArgument (
'user' ,
InputArgument :: REQUIRED ,
2024-02-13 08:37:09 -05:00
'Login to add app password for'
2020-11-23 17:10:48 -05:00
)
-> addOption (
'password-from-env' ,
null ,
InputOption :: VALUE_NONE ,
2022-03-23 13:44:16 -04:00
'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.'
2020-11-23 17:10:48 -05:00
)
2025-10-06 12:37:03 -04:00
-> addOption (
'name' ,
null ,
InputOption :: VALUE_REQUIRED ,
'Name for the app password, defaults to "cli".'
)
2020-11-23 17:10:48 -05:00
;
}
protected function execute ( InputInterface $input , OutputInterface $output ) : int {
$username = $input -> getArgument ( 'user' );
2022-03-23 13:44:16 -04:00
$password = null ;
2020-11-23 17:10:48 -05:00
$user = $this -> userManager -> get ( $username );
if ( is_null ( $user )) {
2022-09-21 11:44:32 -04:00
$output -> writeln ( '<error>Account does not exist</error>' );
2020-11-23 17:10:48 -05:00
return 1 ;
}
if ( $input -> getOption ( 'password-from-env' )) {
2025-06-20 05:20:37 -04:00
$password = getenv ( 'NC_PASS' ) ? : getenv ( 'OC_PASS' );
2020-11-23 17:10:48 -05:00
if ( ! $password ) {
2025-06-20 05:20:37 -04:00
$output -> writeln ( '<error>--password-from-env given, but NC_PASS/OC_PASS is empty!</error>' );
2020-11-23 17:10:48 -05:00
return 1 ;
}
} elseif ( $input -> isInteractive ()) {
/** @var QuestionHelper $helper */
$helper = $this -> getHelper ( 'question' );
2022-09-21 11:44:32 -04:00
$question = new Question ( 'Enter the account password: ' );
2020-11-23 17:10:48 -05:00
$question -> setHidden ( true );
2022-03-23 13:44:16 -04:00
/** @var null|string $password */
2020-11-23 17:10:48 -05:00
$password = $helper -> ask ( $input , $output , $question );
}
2022-03-23 13:44:16 -04:00
if ( $password === null ) {
$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>' );
}
2020-11-23 17:10:48 -05:00
2025-10-06 12:37:03 -04:00
$tokenName = $input -> getOption ( 'name' ) ? : 'cli' ;
2024-09-19 05:10:31 -04:00
$token = $this -> random -> generate ( 72 , ISecureRandom :: CHAR_UPPER . ISecureRandom :: CHAR_LOWER . ISecureRandom :: CHAR_DIGITS );
2022-03-10 09:25:22 -05:00
$generatedToken = $this -> tokenProvider -> generateToken (
2020-11-23 17:10:48 -05:00
$token ,
$user -> getUID (),
2021-05-11 14:38:54 -04:00
$user -> getUID (),
2020-11-23 17:10:48 -05:00
$password ,
2025-10-06 12:37:03 -04:00
$tokenName ,
2020-11-23 17:10:48 -05:00
IToken :: PERMANENT_TOKEN ,
IToken :: DO_NOT_REMEMBER
);
2022-03-10 09:25:22 -05:00
$this -> eventDispatcher -> dispatchTyped (
new AppPasswordCreatedEvent ( $generatedToken )
);
2020-11-23 17:10:48 -05:00
$output -> writeln ( 'app password:' );
$output -> writeln ( $token );
return 0 ;
}
}