1<?php 2/* 3 * vim:set softtabstop=4 shiftwidth=4 expandtab: 4 * 5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later) 6 * Copyright 2001 - 2020 Ampache.org 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 * 21 */ 22 23declare(strict_types=0); 24 25namespace Ampache\Module\Application\Register; 26 27use Ampache\Config\ConfigContainerInterface; 28use Ampache\Config\ConfigurationKeyEnum; 29use Ampache\Repository\Model\ModelFactoryInterface; 30use Ampache\Repository\Model\User; 31use Ampache\Module\Application\ApplicationActionInterface; 32use Ampache\Module\Application\Exception\AccessDeniedException; 33use Ampache\Module\Authorization\GuiGatekeeperInterface; 34use Ampache\Module\System\AmpError; 35use Ampache\Module\System\Core; 36use Ampache\Module\User\Registration; 37use Ampache\Module\Util\Captcha\captcha; 38use Ampache\Module\Util\Mailer; 39use Ampache\Module\Util\Ui; 40use Ampache\Module\Util\UiInterface; 41use Ampache\Repository\UserRepositoryInterface; 42use Psr\Http\Message\ResponseInterface; 43use Psr\Http\Message\ServerRequestInterface; 44 45final class AddUserAction implements ApplicationActionInterface 46{ 47 public const REQUEST_KEY = 'add_user'; 48 49 private ConfigContainerInterface $configContainer; 50 51 private ModelFactoryInterface $modelFactory; 52 53 private UiInterface $ui; 54 55 private UserRepositoryInterface $userRepository; 56 57 public function __construct( 58 ConfigContainerInterface $configContainer, 59 ModelFactoryInterface $modelFactory, 60 UiInterface $ui, 61 UserRepositoryInterface $userRepository 62 ) { 63 $this->configContainer = $configContainer; 64 $this->modelFactory = $modelFactory; 65 $this->ui = $ui; 66 $this->userRepository = $userRepository; 67 } 68 69 public function run(ServerRequestInterface $request, GuiGatekeeperInterface $gatekeeper): ?ResponseInterface 70 { 71 /* Check Perms */ 72 if ( 73 $this->configContainer->isFeatureEnabled(ConfigurationKeyEnum::ALLOW_PUBLIC_REGISTRATION) === false 74 ) { 75 throw new AccessDeniedException('Error attempted registration'); 76 } 77 78 /* Don't even include it if we aren't going to use it */ 79 if ($this->configContainer->isFeatureEnabled(ConfigurationKeyEnum::CAPTCHA_PUBLIC_REG) === true) { 80 define('CAPTCHA_INVERSE', 1); 81 /** 82 * @todo broken, the path does not exist anylonger 83 */ 84 define( 85 'CAPTCHA_BASE_URL', 86 sprintf( 87 '%s/modules/captcha/captcha.php', 88 $this->configContainer->getWebPath() 89 ) 90 ); 91 require_once __DIR__ . '/../../Util/Captcha/init.php'; 92 } 93 /** 94 * User information has been entered 95 * we need to check the database for possible existing username first 96 * if username exists, error and say "Please choose a different name." 97 * if username does not exist, insert user information into database 98 * then allow the user to 'click here to login' 99 * possibly by logging them in right then and there with their current info 100 * and 'click here to login' would just be a link back to index.php 101 */ 102 $fullname = (string) scrub_in(Core::get_post('fullname')); 103 $username = (string) scrub_in(Core::get_post('username')); 104 $email = (string) scrub_in(Core::get_post('email')); 105 $pass1 = Core::get_post('password_1'); 106 $pass2 = Core::get_post('password_2'); 107 $website = (string) scrub_in(Core::get_post('website')); 108 $state = (string) scrub_in(Core::get_post('state')); 109 $city = (string) scrub_in(Core::get_post('city')); 110 111 if ($website === null) { 112 $website = ''; 113 } 114 if ($state === null) { 115 $state = ''; 116 } 117 if ($city === null) { 118 $city = ''; 119 } 120 121 /* If we're using the captcha stuff */ 122 if ($this->configContainer->isFeatureEnabled(ConfigurationKeyEnum::CAPTCHA_PUBLIC_REG) === true) { 123 $captcha = captcha::solved(); 124 if (!isset($captcha)) { 125 AmpError::add('captcha', T_('Captcha is required')); 126 } 127 if (isset($captcha)) { 128 if ($captcha) { 129 $msg="SUCCESS"; 130 } else { 131 AmpError::add('captcha', T_('Captcha failed')); 132 } 133 } // end if we've got captcha 134 } // end if it's enabled 135 136 if ($this->configContainer->isFeatureEnabled(ConfigurationKeyEnum::USER_AGREEMENT) === true) { 137 if (!$_POST['accept_agreement']) { 138 AmpError::add('user_agreement', T_('You must accept the user agreement')); 139 } 140 } // if they have to agree to something 141 142 if (!filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES)) { 143 AmpError::add('username', T_('You must enter a Username')); 144 } 145 146 // Check the mail for correct address formation. 147 if (!Mailer::validate_address($email)) { 148 AmpError::add('email', T_('Invalid e-mail address')); 149 } 150 151 $mandatory_fields = (array) $this->configContainer->get(ConfigurationKeyEnum::REGISTRATION_MANDATORY_FIELDS); 152 if (in_array('fullname', $mandatory_fields) && !$fullname) { 153 AmpError::add('fullname', T_("Please fill in your full name (first name, last name)")); 154 } 155 if (in_array('website', $mandatory_fields) && !$website) { 156 AmpError::add('website', T_("Please fill in your website")); 157 } 158 if (in_array('state', $mandatory_fields) && !$state) { 159 AmpError::add('state', T_("Please fill in your state")); 160 } 161 if (in_array('city', $mandatory_fields) && !$city) { 162 AmpError::add('city', T_("Please fill in your city")); 163 } 164 165 if (!$pass1) { 166 AmpError::add('password', T_('You must enter a password')); 167 } 168 169 if ($pass1 != $pass2) { 170 AmpError::add('password', T_('Passwords do not match')); 171 } 172 173 if ($this->userRepository->findByUsername((string) $username) !== null) { 174 AmpError::add('duplicate_user', T_('That Username already exists')); 175 } 176 177 // If we've hit an error anywhere up there break! 178 if (AmpError::occurred()) { 179 require_once Ui::find_template('show_user_registration.inc.php'); 180 181 return null; 182 } 183 184 /* Attempt to create the new user */ 185 $access = 5; 186 switch ($this->configContainer->get(ConfigurationKeyEnum::AUTO_USER)) { 187 case 'admin': 188 $access = 100; 189 break; 190 case 'user': 191 $access = 25; 192 break; 193 case 'guest': 194 default: 195 $access = 5; 196 break; 197 } // auto-user level 198 199 $userId = User::create( 200 $username, 201 $fullname, 202 $email, 203 (string) $website, 204 $pass1, 205 $access, 206 (string) $state, 207 (string) $city, 208 $this->configContainer->isFeatureEnabled(ConfigurationKeyEnum::ADMIN_ENABLE_REQUIRED) 209 ); 210 211 if ($userId <= 0) { 212 AmpError::add('duplicate_user', T_("Failed to create user")); 213 require_once Ui::find_template('show_user_registration.inc.php'); 214 215 return null; 216 } 217 218 if ($this->configContainer->isFeatureEnabled(ConfigurationKeyEnum::USER_NO_EMAIL_CONFIRM) === false) { 219 $client = $this->modelFactory->createUser($userId); 220 $validation = md5(uniqid((string) rand(), true)); 221 $client->update_validation($validation); 222 223 // Notify user and/or admins 224 Registration::send_confirmation($username, $fullname, $email, $website, $validation); 225 } 226 227 require_once Ui::find_template('show_registration_confirmation.inc.php'); 228 229 return null; 230 } 231} 232