@@ -345,6 +345,47 @@ public function formUserEdit($user_id){
345345 ]);
346346 }
347347
348+ /**
349+ * Renders the form for editing a user's password.
350+ *
351+ * This does NOT render a complete page. Instead, it renders the HTML for the form, which can be embedded in other pages.
352+ * This page requires authentication.
353+ * Request type: GET
354+ */
355+ public function formUserEditPassword ($ user_id ){
356+ // Get the user to edit
357+ $ target_user = User::find ($ user_id );
358+
359+ // Access-controlled resource
360+ if (!$ this ->_app ->user ->checkAccess ('uri_users ' ) && !$ this ->_app ->user ->checkAccess ('uri_group_users ' , ['primary_group_id ' => $ target_user ->primary_group_id ])){
361+ $ this ->_app ->notFound ();
362+ }
363+
364+ $ get = $ this ->_app ->request ->get ();
365+
366+ // Determine authorized fields
367+ $ hidden_fields = [];
368+
369+ if (!$ this ->_app ->user ->checkAccess ("update_account_setting " , ["user " => $ target_user , "property " => 'password ' ]))
370+ $ hidden_fields [] = 'password ' ;
371+
372+ // Load validator rules
373+ $ schema = new \Fortress \RequestSchema ($ this ->_app ->config ('schema.path ' ) . "/forms/user-update.json " );
374+ $ this ->_app ->jsValidator ->setSchema ($ schema );
375+
376+ // This form posts to the same resource as "update user"
377+ $ this ->_app ->render ("components/common/user-set-password.twig " , [
378+ "box_id " => isset ($ get ['box_id ' ]) ? $ get ['box_id ' ] : 'user-set-password ' ,
379+ "box_title " => "Change User Password " ,
380+ "form_action " => $ this ->_app ->site ->uri ['public ' ] . "/users/u/ $ user_id " ,
381+ "target_user " => $ target_user ,
382+ "fields " => [
383+ "hidden " => $ hidden_fields
384+ ],
385+ "validators " => $ this ->_app ->jsValidator ->rules ()
386+ ]);
387+ }
388+
348389 /**
349390 * Processes the request to create a new user (from the admin controls).
350391 *
@@ -497,7 +538,7 @@ public function updateUser($user_id){
497538 $ ms = $ this ->_app ->alerts ;
498539
499540 // Get the target user
500- $ target_user = UserLoader:: fetch ($ user_id );
541+ $ target_user = User:: find ($ user_id );
501542
502543 // Get the target user's groups
503544 $ groups = $ target_user ->getGroups ();
@@ -515,10 +556,17 @@ public function updateUser($user_id){
515556 $ ms ->addMessageTranslated ("danger " , "ACCESS_DENIED " );
516557 $ this ->_app ->halt (403 );
517558 }
518-
559+
519560 // Remove csrf_token
520561 unset($ post ['csrf_token ' ]);
521-
562+
563+ // Set up Fortress to process the request
564+ $ rf = new \Fortress \HTTPRequestFortress ($ ms , $ requestSchema , $ post );
565+
566+ if (isset ($ post ['passwordc ' ])){
567+ unset($ post ['passwordc ' ]);
568+ }
569+
522570 // Check authorization for submitted fields, if the value has been changed
523571 foreach ($ post as $ name => $ value ) {
524572 if ($ name == "groups " || (isset ($ target_user ->$ name ) && $ post [$ name ] != $ target_user ->$ name )){
@@ -532,29 +580,30 @@ public function updateUser($user_id){
532580 $ this ->_app ->halt (400 );
533581 }
534582 }
535-
583+
536584 // Check that we are not disabling the master account
537585 if (($ target_user ->id == $ this ->_app ->config ('user_id_master ' )) && isset ($ post ['flag_enabled ' ]) && $ post ['flag_enabled ' ] == "0 " ){
538586 $ ms ->addMessageTranslated ("danger " , "ACCOUNT_DISABLE_MASTER " );
539587 $ this ->_app ->halt (403 );
540588 }
541-
589+
590+ // Check that the email address is not in use
542591 if (isset ($ post ['email ' ]) && $ post ['email ' ] != $ target_user ->email && UserLoader::exists ($ post ['email ' ], 'email ' )){
543592 $ ms ->addMessageTranslated ("danger " , "ACCOUNT_EMAIL_IN_USE " , $ post );
544593 $ this ->_app ->halt (400 );
545594 }
546595
547- // Set up Fortress to process the request
548- $ rf = new \Fortress \HTTPRequestFortress ($ ms , $ requestSchema , $ post );
549-
550596 // Sanitize
551597 $ rf ->sanitize ();
552598
553599 // Validate, and halt on validation errors.
554600 if (!$ rf ->validate ()) {
555601 $ this ->_app ->halt (400 );
556602 }
557-
603+
604+ // Remove passwordc
605+ $ rf ->removeFields (['passwordc ' ]);
606+
558607 // Get the filtered data
559608 $ data = $ rf ->data ();
560609
@@ -570,6 +619,11 @@ public function updateUser($user_id){
570619 unset($ data ['groups ' ]);
571620 }
572621
622+ // Hash password
623+ if (isset ($ data ['password ' ])){
624+ $ data ['password ' ] = Authentication::hashPassword ($ data ['password ' ]);
625+ }
626+
573627 // Update the user and generate success messages
574628 foreach ($ data as $ name => $ value ){
575629 if ($ value != $ target_user ->$ name ){
@@ -587,9 +641,39 @@ public function updateUser($user_id){
587641 }
588642 }
589643
590- $ ms ->addMessageTranslated ("success " , "ACCOUNT_DETAILS_UPDATED " , ["user_name " => $ target_user ->user_name ]);
591- $ target_user ->store ();
644+ // If we're generating a password reset, create the corresponding event and shoot off an email
645+ if (isset ($ data ['flag_password_reset ' ]) && ($ data ['flag_password_reset ' ] == "1 " )){
646+ // Recheck auth
647+ if (!$ this ->_app ->user ->checkAccess ('update_account_setting ' , ['user ' => $ target_user , 'property ' => 'flag_password_reset ' ])){
648+ $ ms ->addMessageTranslated ("danger " , "ACCESS_DENIED " );
649+ $ this ->_app ->halt (403 );
650+ }
651+ // New password reset event - bypass any rate limiting
652+ $ target_user ->newEventPasswordReset ();
653+ $ target_user ->save ();
654+ // Email the user asking to confirm this change password request
655+ $ twig = $ this ->_app ->view ()->getEnvironment ();
656+ $ template = $ twig ->loadTemplate ("mail/password-reset.twig " );
657+ $ notification = new Notification ($ template );
658+ $ notification ->fromWebsite (); // Automatically sets sender and reply-to
659+ $ notification ->addEmailRecipient ($ target_user ->email , $ target_user ->display_name , [
660+ "user " => $ target_user ,
661+ "request_date " => date ("Y-m-d H:i:s " )
662+ ]);
663+
664+ try {
665+ $ notification ->send ();
666+ } catch (\Exception \phpmailerException $ e ){
667+ $ ms ->addMessageTranslated ("danger " , "MAIL_ERROR " );
668+ error_log ('Mailer Error: ' . $ e ->errorMessage ());
669+ $ this ->_app ->halt (500 );
670+ }
671+
672+ $ ms ->addMessageTranslated ("success " , "FORGOTPASS_REQUEST_SENT " , ["user_name " => $ target_user ->user_name ]);
673+ }
592674
675+ $ ms ->addMessageTranslated ("success " , "ACCOUNT_DETAILS_UPDATED " , ["user_name " => $ target_user ->user_name ]);
676+ $ target_user ->save ();
593677 }
594678
595679 /**
0 commit comments