2525 */
2626namespace OC \Core \Command \User ;
2727
28+ use Egulias \EmailValidator \EmailValidator ;
29+ use Egulias \EmailValidator \Validation \RFCValidation ;
2830use OC \Files \Filesystem ;
31+ use OCA \Settings \Mailer \NewUserMailHelper ;
32+ use OCP \EventDispatcher \IEventDispatcher ;
33+ use OCP \IConfig ;
2934use OCP \IGroup ;
3035use OCP \IGroupManager ;
3136use OCP \IUser ;
3237use OCP \IUserManager ;
38+ use OCP \Security \Events \GenerateSecurePasswordEvent ;
39+ use OCP \Security \ISecureRandom ;
3340use Symfony \Component \Console \Command \Command ;
3441use Symfony \Component \Console \Helper \QuestionHelper ;
3542use Symfony \Component \Console \Input \InputArgument ;
3946use Symfony \Component \Console \Question \Question ;
4047
4148class Add extends Command {
49+ /**
50+ * @var IUserManager
51+ */
52+ protected $ userManager ;
53+
54+ /**
55+ * @var IGroupManager
56+ */
57+ protected $ groupManager ;
58+
59+ /**
60+ * @var EmailValidator
61+ */
62+ protected $ emailValidator ;
63+
64+ /**
65+ * @var IConfig
66+ */
67+ private $ config ;
68+
69+ /**
70+ * @var NewUserMailHelper
71+ */
72+ private $ mailHelper ;
73+
74+ /**
75+ * @var IEventDispatcher
76+ */
77+ private $ eventDispatcher ;
78+
79+ /**
80+ * @var ISecureRandom
81+ */
82+ private $ secureRandom ;
83+
84+ /**
85+ * @param IUserManager $userManager
86+ * @param IGroupManager $groupManager
87+ * @param EmailValidator $emailValidator
88+ */
4289 public function __construct (
43- protected IUserManager $ userManager ,
44- protected IGroupManager $ groupManager ,
90+ IUserManager $ userManager ,
91+ IGroupManager $ groupManager ,
92+ EmailValidator $ emailValidator ,
93+ IConfig $ config ,
94+ NewUserMailHelper $ mailHelper ,
95+ IEventDispatcher $ eventDispatcher ,
96+ ISecureRandom $ secureRandom
4597 ) {
4698 parent ::__construct ();
99+ $ this ->userManager = $ userManager ;
100+ $ this ->groupManager = $ groupManager ;
101+ $ this ->emailValidator = $ emailValidator ;
102+ $ this ->config = $ config ;
103+ $ this ->mailHelper = $ mailHelper ;
104+ $ this ->eventDispatcher = $ eventDispatcher ;
105+ $ this ->secureRandom = $ secureRandom ;
47106 }
48107
49108 protected function configure () {
@@ -72,18 +131,30 @@ protected function configure() {
72131 'g ' ,
73132 InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY ,
74133 'groups the user should be added to (The group will be created if it does not exist) '
134+ )
135+ ->addOption (
136+ 'email ' ,
137+ null ,
138+ InputOption::VALUE_REQUIRED ,
139+ 'When set, users may register using the default E-Mail verification workflow '
75140 );
76141 }
77142
78143 protected function execute (InputInterface $ input , OutputInterface $ output ): int {
79144 $ uid = $ input ->getArgument ('uid ' );
145+ $ emailIsSet = \is_string ($ input ->getOption ('email ' )) && \mb_strlen ($ input ->getOption ('email ' )) > 0 ;
146+ $ emailIsValid = $ this ->emailValidator ->isValid ($ input ->getOption ('email ' ) ?? '' , new RFCValidation ());
147+ $ password = '' ;
148+ $ temporaryPassword = '' ;
149+
80150 if ($ this ->userManager ->userExists ($ uid )) {
81151 $ output ->writeln ('<error>The user " ' . $ uid . '" already exists.</error> ' );
82152 return 1 ;
83153 }
84154
85155 if ($ input ->getOption ('password-from-env ' )) {
86156 $ password = getenv ('OC_PASS ' );
157+
87158 if (!$ password ) {
88159 $ output ->writeln ('<error>--password-from-env given, but OC_PASS is empty!</error> ' );
89160 return 1 ;
@@ -109,17 +180,32 @@ protected function execute(InputInterface $input, OutputInterface $output): int
109180 return 1 ;
110181 }
111182
183+ if (trim ($ password ) === '' && $ emailIsSet ) {
184+ if ($ emailIsValid ) {
185+ $ output ->writeln ('Setting a temporary password. ' );
186+
187+ $ temporaryPassword = $ this ->getTemporaryPassword ();
188+ } else {
189+ $ output ->writeln (\sprintf (
190+ '<error>The given E-Mail address "%s" is invalid: %s</error> ' ,
191+ $ input ->getOption ('email ' ),
192+ $ this ->emailValidator ->getError ()->description ()
193+ ));
194+
195+ return 1 ;
196+ }
197+ }
198+
112199 try {
113200 $ user = $ this ->userManager ->createUser (
114201 $ input ->getArgument ('uid ' ),
115- $ password
202+ $ password ?: $ temporaryPassword
116203 );
117204 } catch (\Exception $ e ) {
118205 $ output ->writeln ('<error> ' . $ e ->getMessage () . '</error> ' );
119206 return 1 ;
120207 }
121208
122-
123209 if ($ user instanceof IUser) {
124210 $ output ->writeln ('<info>The user " ' . $ user ->getUID () . '" was created successfully</info> ' );
125211 } else {
@@ -129,7 +215,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int
129215
130216 if ($ input ->getOption ('display-name ' )) {
131217 $ user ->setDisplayName ($ input ->getOption ('display-name ' ));
132- $ output ->writeln ('Display name set to " ' . $ user ->getDisplayName () . '" ' );
218+ $ output ->writeln (sprintf ('Display name set to "%s" ' , $ user ->getDisplayName ()));
219+ }
220+
221+ if ($ emailIsSet && $ emailIsValid ) {
222+ $ user ->setSystemEMailAddress ($ input ->getOption ('email ' ));
223+ $ output ->writeln (sprintf ('E-Mail set to "%s" ' , (string ) $ user ->getSystemEMailAddress ()));
224+
225+ if (trim ($ password ) === '' && $ this ->config ->getAppValue ('core ' , 'newUser.sendEmail ' , 'yes ' ) === 'yes ' ) {
226+ try {
227+ $ this ->mailHelper ->sendMail (
228+ $ user ,
229+ $ this ->mailHelper ->generateTemplate ($ user , true )
230+ );
231+ $ output ->writeln ('Invitation E-Mail sent. ' );
232+ } catch (\Exception $ e ) {
233+ $ output ->writeln (\sprintf ('Unable to send the invitation mail to %s ' , $ user ->getEMailAddress ()));
234+ }
235+ }
133236 }
134237
135238 $ groups = $ input ->getOption ('group ' );
@@ -156,4 +259,16 @@ protected function execute(InputInterface $input, OutputInterface $output): int
156259 }
157260 return 0 ;
158261 }
262+
263+ /**
264+ * @return string
265+ */
266+ protected function getTemporaryPassword (): string
267+ {
268+ $ passwordEvent = new GenerateSecurePasswordEvent ();
269+
270+ $ this ->eventDispatcher ->dispatchTyped ($ passwordEvent );
271+
272+ return $ passwordEvent ->getPassword () ?? $ this ->secureRandom ->generate (20 );
273+ }
159274}
0 commit comments