Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
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.

Register.php 13 KiB

10 months ago
10 months ago
10 months ago
10 months ago
1 year ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. <?php
  2. namespace Friendica\Module;
  3. use Friendica\BaseModule;
  4. use Friendica\Content\Text\BBCode;
  5. use Friendica\Core\Config;
  6. use Friendica\Core\Hook;
  7. use Friendica\Core\L10n;
  8. use Friendica\Core\L10n\L10n as L10nClass;
  9. use Friendica\Core\Logger;
  10. use Friendica\Core\Renderer;
  11. use Friendica\Core\Worker;
  12. use Friendica\Database\DBA;
  13. use Friendica\DI;
  14. use Friendica\Model;
  15. use Friendica\Util\Strings;
  16. /**
  17. * @author Hypolite Petovan <hypolite@mrpetovan.com>
  18. */
  19. class Register extends BaseModule
  20. {
  21. const CLOSED = 0;
  22. const APPROVE = 1;
  23. const OPEN = 2;
  24. /**
  25. * @brief Module GET method to display any content
  26. *
  27. * Extend this method if the module is supposed to return any display
  28. * through a GET request. It can be an HTML page through templating or a
  29. * XML feed or a JSON output.
  30. *
  31. * @return string
  32. */
  33. public static function content(array $parameters = [])
  34. {
  35. // logged in users can register others (people/pages/groups)
  36. // even with closed registrations, unless specifically prohibited by site policy.
  37. // 'block_extended_register' blocks all registrations, period.
  38. $block = Config::get('system', 'block_extended_register');
  39. if (local_user() && $block) {
  40. notice(L10n::t('Permission denied.'));
  41. return '';
  42. }
  43. if (local_user()) {
  44. $user = DBA::selectFirst('user', ['parent-uid'], ['uid' => local_user()]);
  45. if (!empty($user['parent-uid'])) {
  46. notice(L10n::t('Only parent users can create additional accounts.'));
  47. return '';
  48. }
  49. }
  50. if (!local_user() && (intval(Config::get('config', 'register_policy')) === self::CLOSED)) {
  51. notice(L10n::t('Permission denied.'));
  52. return '';
  53. }
  54. $max_dailies = intval(Config::get('system', 'max_daily_registrations'));
  55. if ($max_dailies) {
  56. $count = DBA::count('user', ['`register_date` > UTC_TIMESTAMP - INTERVAL 1 day']);
  57. if ($count >= $max_dailies) {
  58. Logger::log('max daily registrations exceeded.');
  59. notice(L10n::t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.'));
  60. return '';
  61. }
  62. }
  63. $username = $_REQUEST['username'] ?? '';
  64. $email = $_REQUEST['email'] ?? '';
  65. $openid_url = $_REQUEST['openid_url'] ?? '';
  66. $nickname = $_REQUEST['nickname'] ?? '';
  67. $photo = $_REQUEST['photo'] ?? '';
  68. $invite_id = $_REQUEST['invite_id'] ?? '';
  69. if (local_user() || Config::get('system', 'no_openid')) {
  70. $fillwith = '';
  71. $fillext = '';
  72. $oidlabel = '';
  73. } else {
  74. $fillwith = L10n::t('You may (optionally) fill in this form via OpenID by supplying your OpenID and clicking "Register".');
  75. $fillext = L10n::t('If you are not familiar with OpenID, please leave that field blank and fill in the rest of the items.');
  76. $oidlabel = L10n::t('Your OpenID (optional): ');
  77. }
  78. if (Config::get('system', 'publish_all')) {
  79. $profile_publish = '<input type="hidden" name="profile_publish_reg" value="1" />';
  80. } else {
  81. $publish_tpl = Renderer::getMarkupTemplate('profile_publish.tpl');
  82. $profile_publish = Renderer::replaceMacros($publish_tpl, [
  83. '$instance' => 'reg',
  84. '$pubdesc' => L10n::t('Include your profile in member directory?'),
  85. '$yes_selected' => '',
  86. '$no_selected' => ' checked="checked"',
  87. '$str_yes' => L10n::t('Yes'),
  88. '$str_no' => L10n::t('No'),
  89. ]);
  90. }
  91. $ask_password = !DBA::count('contact');
  92. $tpl = Renderer::getMarkupTemplate('register.tpl');
  93. $arr = ['template' => $tpl];
  94. Hook::callAll('register_form', $arr);
  95. $tpl = $arr['template'];
  96. $tos = new Tos();
  97. $o = Renderer::replaceMacros($tpl, [
  98. '$invitations' => Config::get('system', 'invitation_only'),
  99. '$permonly' => intval(Config::get('config', 'register_policy')) === self::APPROVE,
  100. '$permonlybox' => ['permonlybox', L10n::t('Note for the admin'), '', L10n::t('Leave a message for the admin, why you want to join this node'), 'required'],
  101. '$invite_desc' => L10n::t('Membership on this site is by invitation only.'),
  102. '$invite_label' => L10n::t('Your invitation code: '),
  103. '$invite_id' => $invite_id,
  104. '$regtitle' => L10n::t('Registration'),
  105. '$registertext' => BBCode::convert(Config::get('config', 'register_text', '')),
  106. '$fillwith' => $fillwith,
  107. '$fillext' => $fillext,
  108. '$oidlabel' => $oidlabel,
  109. '$openid' => $openid_url,
  110. '$namelabel' => L10n::t('Your Full Name (e.g. Joe Smith, real or real-looking): '),
  111. '$addrlabel' => L10n::t('Your Email Address: (Initial information will be send there, so this has to be an existing address.)'),
  112. '$addrlabel2' => L10n::t('Please repeat your e-mail address:'),
  113. '$ask_password' => $ask_password,
  114. '$password1' => ['password1', L10n::t('New Password:'), '', L10n::t('Leave empty for an auto generated password.')],
  115. '$password2' => ['confirm', L10n::t('Confirm:'), '', ''],
  116. '$nickdesc' => L10n::t('Choose a profile nickname. This must begin with a text character. Your profile address on this site will then be "<strong>nickname@%s</strong>".', DI::baseUrl()->getHostname()),
  117. '$nicklabel' => L10n::t('Choose a nickname: '),
  118. '$photo' => $photo,
  119. '$publish' => $profile_publish,
  120. '$regbutt' => L10n::t('Register'),
  121. '$username' => $username,
  122. '$email' => $email,
  123. '$nickname' => $nickname,
  124. '$sitename' => DI::baseUrl()->getHostname(),
  125. '$importh' => L10n::t('Import'),
  126. '$importt' => L10n::t('Import your profile to this friendica instance'),
  127. '$showtoslink' => Config::get('system', 'tosdisplay'),
  128. '$tostext' => L10n::t('Terms of Service'),
  129. '$showprivstatement' => Config::get('system', 'tosprivstatement'),
  130. '$privstatement'=> $tos->privacy_complete,
  131. '$form_security_token' => BaseModule::getFormSecurityToken('register'),
  132. '$explicit_content' => Config::get('system', 'explicit_content', false),
  133. '$explicit_content_note' => L10n::t('Note: This node explicitly contains adult content'),
  134. '$additional' => !empty(local_user()),
  135. '$parent_password' => ['parent_password', L10n::t('Parent Password:'), '', L10n::t('Please enter the password of the parent account to legitimize your request.')]
  136. ]);
  137. return $o;
  138. }
  139. /**
  140. * @brief Module POST method to process submitted data
  141. *
  142. * Extend this method if the module is supposed to process POST requests.
  143. * Doesn't display any content
  144. */
  145. public static function post(array $parameters = [])
  146. {
  147. BaseModule::checkFormSecurityTokenRedirectOnError('/register', 'register');
  148. $a = DI::app();
  149. $arr = ['post' => $_POST];
  150. Hook::callAll('register_post', $arr);
  151. $additional_account = false;
  152. if (!local_user() && !empty($arr['post']['parent_password'])) {
  153. notice(L10n::t('Permission denied.'));
  154. return;
  155. } elseif (local_user() && !empty($arr['post']['parent_password'])) {
  156. try {
  157. Model\User::getIdFromPasswordAuthentication(local_user(), $arr['post']['parent_password']);
  158. } catch (\Exception $ex) {
  159. notice(L10n::t("Password doesn't match."));
  160. $regdata = ['nickname' => $arr['post']['nickname'], 'username' => $arr['post']['username']];
  161. DI::baseUrl()->redirect('register?' . http_build_query($regdata));
  162. }
  163. $additional_account = true;
  164. } elseif (local_user()) {
  165. notice(L10n::t('Please enter your password.'));
  166. $regdata = ['nickname' => $arr['post']['nickname'], 'username' => $arr['post']['username']];
  167. DI::baseUrl()->redirect('register?' . http_build_query($regdata));
  168. }
  169. $max_dailies = intval(Config::get('system', 'max_daily_registrations'));
  170. if ($max_dailies) {
  171. $count = DBA::count('user', ['`register_date` > UTC_TIMESTAMP - INTERVAL 1 day']);
  172. if ($count >= $max_dailies) {
  173. return;
  174. }
  175. }
  176. switch (Config::get('config', 'register_policy')) {
  177. case self::OPEN:
  178. $blocked = 0;
  179. $verified = 1;
  180. break;
  181. case self::APPROVE:
  182. $blocked = 1;
  183. $verified = 0;
  184. break;
  185. case self::CLOSED:
  186. default:
  187. if (empty($_SESSION['authenticated']) && empty($_SESSION['administrator'])) {
  188. notice(L10n::t('Permission denied.'));
  189. return;
  190. }
  191. $blocked = 1;
  192. $verified = 0;
  193. break;
  194. }
  195. $netpublish = !empty($_POST['profile_publish_reg']);
  196. $arr = $_POST;
  197. // Is there text in the tar pit?
  198. if (!empty($arr['email'])) {
  199. Logger::info('Tar pit', $arr);
  200. notice(L10n::t('You have entered too much information.'));
  201. DI::baseUrl()->redirect('register/');
  202. }
  203. // Overwriting the "tar pit" field with the real one
  204. $arr['email'] = $arr['field1'];
  205. if ($additional_account) {
  206. $user = DBA::selectFirst('user', ['email'], ['uid' => local_user()]);
  207. if (!DBA::isResult($user)) {
  208. notice(L10n::t('User not found.'));
  209. DI::baseUrl()->redirect('register');
  210. }
  211. $blocked = 0;
  212. $verified = 1;
  213. $arr['password1'] = $arr['confirm'] = $arr['parent_password'];
  214. $arr['repeat'] = $arr['email'] = $user['email'];
  215. }
  216. if ($arr['email'] != $arr['repeat']) {
  217. Logger::info('Mail mismatch', $arr);
  218. notice(L10n::t('Please enter the identical mail address in the second field.'));
  219. $regdata = ['email' => $arr['email'], 'nickname' => $arr['nickname'], 'username' => $arr['username']];
  220. DI::baseUrl()->redirect('register?' . http_build_query($regdata));
  221. }
  222. $arr['blocked'] = $blocked;
  223. $arr['verified'] = $verified;
  224. $arr['language'] = L10nClass::detectLanguage($_SERVER, $_GET, DI::config()->get('system', 'language'));
  225. try {
  226. $result = Model\User::create($arr);
  227. } catch (\Exception $e) {
  228. notice($e->getMessage());
  229. return;
  230. }
  231. $user = $result['user'];
  232. $base_url = DI::baseUrl()->get();
  233. if ($netpublish && intval(Config::get('config', 'register_policy')) !== self::APPROVE) {
  234. $url = $base_url . '/profile/' . $user['nickname'];
  235. Worker::add(PRIORITY_LOW, 'Directory', $url);
  236. }
  237. if ($additional_account) {
  238. DBA::update('user', ['parent-uid' => local_user()], ['uid' => $user['uid']]);
  239. info(L10n::t('The additional account was created.'));
  240. DI::baseUrl()->redirect('delegation');
  241. }
  242. $using_invites = Config::get('system', 'invitation_only');
  243. $num_invites = Config::get('system', 'number_invites');
  244. $invite_id = (!empty($_POST['invite_id']) ? Strings::escapeTags(trim($_POST['invite_id'])) : '');
  245. if (intval(Config::get('config', 'register_policy')) === self::OPEN) {
  246. if ($using_invites && $invite_id) {
  247. Model\Register::deleteByHash($invite_id);
  248. DI::pConfig()->set($user['uid'], 'system', 'invites_remaining', $num_invites);
  249. }
  250. // Only send a password mail when the password wasn't manually provided
  251. if (empty($_POST['password1']) || empty($_POST['confirm'])) {
  252. $res = Model\User::sendRegisterOpenEmail(
  253. L10n::withLang($arr['language']),
  254. $user,
  255. Config::get('config', 'sitename'),
  256. $base_url,
  257. $result['password']
  258. );
  259. if ($res) {
  260. info(L10n::t('Registration successful. Please check your email for further instructions.'));
  261. DI::baseUrl()->redirect();
  262. } else {
  263. notice(
  264. L10n::t('Failed to send email message. Here your accout details:<br> login: %s<br> password: %s<br><br>You can change your password after login.',
  265. $user['email'],
  266. $result['password'])
  267. );
  268. }
  269. } else {
  270. info(L10n::t('Registration successful.'));
  271. DI::baseUrl()->redirect();
  272. }
  273. } elseif (intval(Config::get('config', 'register_policy')) === self::APPROVE) {
  274. if (!strlen(Config::get('config', 'admin_email'))) {
  275. notice(L10n::t('Your registration can not be processed.'));
  276. DI::baseUrl()->redirect();
  277. }
  278. // Check if the note to the admin is actually filled out
  279. if (empty($_POST['permonlybox'])) {
  280. notice(L10n::t('You have to leave a request note for the admin.')
  281. . L10n::t('Your registration can not be processed.'));
  282. DI::baseUrl()->redirect('register/');
  283. }
  284. Model\Register::createForApproval($user['uid'], Config::get('system', 'language'), $_POST['permonlybox']);
  285. // invite system
  286. if ($using_invites && $invite_id) {
  287. Model\Register::deleteByHash($invite_id);
  288. DI::pConfig()->set($user['uid'], 'system', 'invites_remaining', $num_invites);
  289. }
  290. // send email to admins
  291. $admins_stmt = DBA::select(
  292. 'user',
  293. ['uid', 'language', 'email'],
  294. ['email' => explode(',', str_replace(' ', '', Config::get('config', 'admin_email')))]
  295. );
  296. // send notification to admins
  297. while ($admin = DBA::fetch($admins_stmt)) {
  298. \notification([
  299. 'type' => NOTIFY_SYSTEM,
  300. 'event' => 'SYSTEM_REGISTER_REQUEST',
  301. 'source_name' => $user['username'],
  302. 'source_mail' => $user['email'],
  303. 'source_nick' => $user['nickname'],
  304. 'source_link' => $base_url . '/admin/users/',
  305. 'link' => $base_url . '/admin/users/',
  306. 'source_photo' => $base_url . '/photo/avatar/' . $user['uid'] . '.jpg',
  307. 'to_email' => $admin['email'],
  308. 'uid' => $admin['uid'],
  309. 'language' => ($admin['language'] ?? '') ?: 'en',
  310. 'show_in_notification_page' => false
  311. ]);
  312. }
  313. DBA::close($admins_stmt);
  314. // send notification to the user, that the registration is pending
  315. Model\User::sendRegisterPendingEmail(
  316. $user,
  317. Config::get('config', 'sitename'),
  318. $base_url,
  319. $result['password']
  320. );
  321. info(L10n::t('Your registration is pending approval by the site owner.'));
  322. DI::baseUrl()->redirect();
  323. }
  324. return;
  325. }
  326. }