/** * Add "x email-confirmed open account requests" notice * @param $notice * @return bool */ public static function confirmAccountsNotice(OutputPage &$out, Skin &$skin) { global $wgConfirmAccountNotice; $context = $out->getContext(); if (!$wgConfirmAccountNotice || !$context->getUser()->isAllowed('confirmaccount')) { return true; } # Only show on some special pages $title = $context->getTitle(); if (!$title->isSpecial('Recentchanges') && !$title->isSpecial('Watchlist')) { return true; } $count = ConfirmAccount::getOpenEmailConfirmedCount('*'); if ($count > 0) { $out->prependHtml('<div id="mw-confirmaccount-msg" class="plainlinks mw-confirmaccount-bar">' . $out->parse(wfMsgExt('confirmaccount-newrequests', 'parsemag', $count), false) . '</div>'); $out->addModules('ext.confirmAccount'); // CSS } return true; }
protected function createUserPage(User $user) { global $wgMakeUserPageFromBio, $wgAutoUserBioText; global $wgConfirmAccountSortkey, $wgContLang; $body = ''; // page text if ($wgMakeUserPageFromBio) { # Add account request bio to userpage $body .= $this->bio; # Add any automatic text for all confirmed accounts if ($wgAutoUserBioText != '') { $body .= "\n\n{$wgAutoUserBioText}"; } } # Add any automatic text for confirmed accounts of this type $autoText = self::getAutoTextFromType($this->type); if ($autoText != '') { $body .= "\n\n{$autoText}"; } # Add any areas of interest categories... foreach (ConfirmAccount::getUserAreaConfig() as $name => $conf) { if (in_array($name, $this->areas)) { # General userpage text for anyone with this interest if ($conf['userText'] != '') { $body .= $conf['userText']; } # Message for users with this interested with the given account type if (isset($conf['grpUserText'][$this->type]) && $conf['grpUserText'][$this->type] != '') { $body .= $conf['grpUserText']; } } } # Set sortkey and use it on userpage. This can be used to # normalize things like firstname, lastname and so fourth. if (!empty($wgConfirmAccountSortkey)) { $sortKey = preg_replace($wgConfirmAccountSortkey[0], $wgConfirmAccountSortkey[1], $user->getUserPage()->getText()); $body .= "\n{{DEFAULTSORT:{$sortKey}}}"; # Clean up any other categories... $catNS = $wgContLang->getNSText(NS_CATEGORY); $replace = '/\\[\\[' . preg_quote($catNS) . ':([^\\]]+)\\]\\]/i'; // [[Category:x]] $with = "[[{$catNS}:\$1|" . str_replace('$', '\\$', $sortKey) . "]]"; // [[Category:x|sortkey]] $body = preg_replace($replace, $with, $body); } # Create userpage! $article = new WikiPage($user->getUserPage()); $article->doEdit($body, wfMsg('confirmaccount-summary'), EDIT_MINOR); }
protected function showList() { $out = $this->getOutput(); # Output the list $pager = new ConfirmAccountsPager($this, array(), $this->queueType, $this->showRejects, $this->showHeld, $this->showStale); if ($pager->getNumRows()) { if ($this->showStale) { $out->addWikiMsg('confirmaccount-list3'); } elseif ($this->showRejects) { $out->addWikiMsg('confirmaccount-list2'); } else { $out->addWikiMsg('confirmaccount-list'); } $out->addHTML($pager->getNavigationBar()); $out->addHTML($pager->getBody()); $out->addHTML($pager->getNavigationBar()); } else { if ($this->showRejects) { $out->addWikiMsg('confirmaccount-none-r'); } elseif ($this->showStale) { $out->addWikiMsg('confirmaccount-none-e'); } elseif ($this->showHeld) { $out->addWikiMsg('confirmaccount-none-h'); } else { $out->addWikiMsg('confirmaccount-none-o'); } } # Every 30th view, prune old deleted items if (0 == mt_rand(0, 29)) { ConfirmAccount::runAutoMaintenance(); } }
/** * Attempt to validate and submit this data to the DB * @param $context IContextSource * @return array( true or error key string, html error msg or null ) */ public function submit(IContextSource $context) { global $wgAuth, $wgAccountRequestThrottle, $wgMemc, $wgContLang; global $wgConfirmAccountRequestFormItems; $formConfig = $wgConfirmAccountRequestFormItems; // convience $reqUser = $this->requester; # Make sure that basic permissions are checked $block = ConfirmAccount::getAccountRequestBlock($reqUser); if ($block) { return array('accountreq_permission_denied', $context->msg('badaccess-group0')->escaped()); } elseif (wfReadOnly()) { return array('accountreq_readonly', $context->msg('badaccess-group0')->escaped()); } # Now create a dummy user ($u) and check if it is valid if ($this->userName === '') { return array('accountreq_no_name', $context->msg('noname')->escaped()); } $u = User::newFromName($this->userName, 'creatable'); if (!$u) { return array('accountreq_invalid_name', $context->msg('noname')->escaped()); } # No request spamming... if ($wgAccountRequestThrottle && $reqUser->isPingLimitable()) { $key = wfMemcKey('acctrequest', 'ip', $this->ip); $value = (int) $wgMemc->get($key); if ($value > $wgAccountRequestThrottle) { return array('accountreq_throttled', $context->msg('acct_request_throttle_hit', $wgAccountRequestThrottle)->text()); } } # Make sure user agrees to policy here if ($formConfig['TermsOfService']['enabled'] && !$this->tosAccepted) { return array('acct_request_skipped_tos', $context->msg('requestaccount-agree')->escaped()); } # Validate email address if (!Sanitizer::validateEmail($this->email)) { return array('acct_request_invalid_email', $context->msg('invalidemailaddress')->escaped()); } # Check if biography is long enough if ($formConfig['Biography']['enabled'] && str_word_count($this->bio) < $formConfig['Biography']['minWords']) { $minWords = $formConfig['Biography']['minWords']; return array('acct_request_short_bio', $context->msg('requestaccount-tooshort')->numParams($minWords)->text()); } # Per security reasons, file dir cannot be pulled from client, # so ask them to resubmit it then... # If the extra fields are off, then uploads are off $allowFiles = $formConfig['CV']['enabled']; if ($allowFiles && $this->attachmentPrevName && !$this->attachmentSrcName) { # If the user is submitting forgotAttachment as true with no file, # then they saw the notice and choose not to re-select the file. # Assume that they don't want to send one anymore. if (!$this->attachmentDidNotForget) { $this->attachmentPrevName = ''; $this->attachmentDidNotForget = 0; return array(false, $context->msg('requestaccount-resub')->escaped()); } } # Check if already in use if (0 != $u->idForName() || $wgAuth->userExists($u->getName())) { return array('accountreq_username_exists', $context->msg('userexists')->escaped()); } # Set email and real name $u->setEmail($this->email); $u->setRealName($this->realName); $dbw = wfGetDB(DB_MASTER); $dbw->begin(); // ready to acquire locks # Check pending accounts for name use if (!UserAccountRequest::acquireUsername($u->getName())) { $dbw->rollback(); return array('accountreq_username_pending', $context->msg('requestaccount-inuse')->escaped()); } # Check if someone else has an account request with the same email if (!UserAccountRequest::acquireEmail($u->getEmail())) { $dbw->rollback(); return array('acct_request_email_exists', $context->msg('requestaccount-emaildup')->escaped()); } # Process upload... if ($allowFiles && $this->attachmentSrcName) { global $wgAccountRequestExts, $wgConfirmAccountFSRepos; $ext = explode('.', $this->attachmentSrcName); $finalExt = $ext[count($ext) - 1]; # File must have size. if (trim($this->attachmentSrcName) == '' || empty($this->attachmentSize)) { $this->attachmentPrevName = ''; $dbw->rollback(); return array('acct_request_empty_file', $context->msg('emptyfile')->escaped()); } # Look at the contents of the file; if we can recognize the # type but it's corrupt or data of the wrong type, we should # probably not accept it. if (!in_array($finalExt, $wgAccountRequestExts)) { $this->attachmentPrevName = ''; $dbw->rollback(); return array('acct_request_bad_file_ext', $context->msg('requestaccount-exts')->escaped()); } $veri = ConfirmAccount::verifyAttachment($this->attachmentTempPath, $finalExt); if (!$veri->isGood()) { $this->attachmentPrevName = ''; $dbw->rollback(); return array('acct_request_corrupt_file', $context->msg('verification-error')->escaped()); } # Start a transaction, move file from temp to account request directory. $repo = new FSRepo($wgConfirmAccountFSRepos['accountreqs']); $key = sha1_file($this->attachmentTempPath) . '.' . $finalExt; $pathRel = UserAccountRequest::relPathFromKey($key); $triplet = array($this->attachmentTempPath, 'public', $pathRel); $status = $repo->storeBatch(array($triplet), FSRepo::OVERWRITE_SAME); // save! if (!$status->isOk()) { $dbw->rollback(); return array('acct_request_file_store_error', $context->msg('filecopyerror', $this->attachmentTempPath, $pathRel)->escaped()); } } $expires = null; // passed by reference $token = ConfirmAccount::getConfirmationToken($u, $expires); # Insert into pending requests... $req = UserAccountRequest::newFromArray(array('name' => $u->getName(), 'email' => $u->getEmail(), 'real_name' => $u->getRealName(), 'registration' => $this->registration, 'bio' => $this->bio, 'notes' => $this->notes, 'urls' => $this->urls, 'filename' => isset($this->attachmentSrcName) ? $this->attachmentSrcName : null, 'type' => $this->type, 'areas' => $this->areas, 'storage_key' => isset($key) ? $key : null, 'comment' => '', 'email_token' => md5($token), 'email_token_expires' => $expires, 'ip' => $this->ip, 'xff' => $this->xff, 'agent' => $this->agent)); $req->insertOn(); # Send confirmation, required! $result = ConfirmAccount::sendConfirmationMail($u, $this->ip, $token, $expires); if (!$result->isOK()) { $dbw->rollback(); // nevermind if (isset($repo) && isset($pathRel)) { // remove attachment $repo->cleanupBatch(array(array('public', $pathRel))); } $param = $context->getOutput()->parse($result->getWikiText()); return array('acct_request_mail_failed', $context->msg('mailerror')->rawParams($param)->escaped()); } $dbw->commit(); # Clear cache for notice of how many account requests there are ConfirmAccount::clearAccountRequestCountCache(); # No request spamming... if ($wgAccountRequestThrottle && $reqUser->isPingLimitable()) { $ip = $context->getRequest()->getIP(); $key = wfMemcKey('acctrequest', 'ip', $ip); $value = $wgMemc->incr($key); if (!$value) { $wgMemc->set($key, 1, 86400); } } # Done! return array(true, null); }
function showCredentials() { $reqUser = $this->getUser(); $out = $this->getOutput(); $titleObj = SpecialPage::getTitleFor('UserCredentials'); $row = $this->getAccountData(); if (!$row) { $out->addHTML(wfMsgHtml('usercredentials-badid')); return; } $out->addWikiText(wfMsg("usercredentials-text")); $user = User::newFromName($this->target); $list = array(); foreach ($user->getGroups() as $group) { $list[] = self::buildGroupLink($group); } $grouplist = ''; if (count($list) > 0) { $grouplist = '<tr><td>' . wfMsgHtml('usercredentials-member') . '</td><td>' . implode(', ', $list) . '</td></tr>'; } $form = "<fieldset>"; $form .= '<legend>' . wfMsgHtml('usercredentials-leg-user') . '</legend>'; $form .= '<table cellpadding=\'4\'>'; $form .= "<tr><td>" . wfMsgHtml('username') . "</td>"; $form .= "<td>" . Linker::makeLinkObj($user->getUserPage(), htmlspecialchars($user->getUserPage()->getText())) . "</td></tr>\n"; $econf = $row->acd_email_authenticated ? ' <strong>' . wfMsgHtml('confirmaccount-econf') . '</strong>' : ''; $form .= "<tr><td>" . wfMsgHtml('usercredentials-email') . "</td>"; $form .= "<td>" . htmlspecialchars($row->acd_email) . $econf . "</td></tr>\n"; $form .= $grouplist; $form .= '</table></fieldset>'; $areaSet = UserAccountRequest::expandAreas($row->acd_areas); $userAreas = ConfirmAccount::getUserAreaConfig(); if (count($userAreas) > 0) { $form .= '<fieldset>'; $form .= '<legend>' . wfMsgHtml('confirmaccount-leg-areas') . '</legend>'; $form .= "<div style='height:150px; overflow:scroll; background-color:#f9f9f9;'>"; $form .= "<table cellspacing='5' cellpadding='0' style='background-color:#f9f9f9;'><tr valign='top'>"; $count = 0; $att = array('disabled' => 'disabled'); foreach ($userAreas as $name => $conf) { $count++; if ($count > 5) { $form .= "</tr><tr valign='top'>"; $count = 1; } $formName = "wpArea-" . htmlspecialchars(str_replace(' ', '_', $name)); if ($conf['project'] != '') { $pg = Linker::link(Title::newFromText($name), wfMsgHtml('requestaccount-info'), array(), array(), "known"); } else { $pg = ''; } $form .= "<td>" . Xml::checkLabel($name, $formName, $formName, in_array($formName, $areaSet), $att) . " {$pg}</td>\n"; } $form .= "</tr></table></div>"; $form .= '</fieldset>'; } $form .= '<fieldset>'; $form .= '<legend>' . wfMsgHtml('usercredentials-leg-person') . '</legend>'; $form .= '<table cellpadding=\'4\'>'; $form .= "<tr><td>" . wfMsgHtml('usercredentials-real') . "</td>"; $form .= "<td>" . htmlspecialchars($row->acd_real_name) . "</td></tr>\n"; $form .= '</table>'; $form .= "<p>" . wfMsgHtml('usercredentials-bio') . "</p>"; $form .= "<p><textarea tabindex='1' readonly='readonly' name='wpBio' id='wpNewBio' rows='10' cols='80' style='width:100%'>" . htmlspecialchars($row->acd_bio) . "</textarea></p>\n"; $form .= '</fieldset>'; $form .= '<fieldset>'; $form .= '<legend>' . wfMsgHtml('usercredentials-leg-other') . '</legend>'; global $wgAccountRequestExtraInfo; if ($wgAccountRequestExtraInfo) { $form .= '<p>' . wfMsgHtml('usercredentials-attach') . ' '; if ($row->acd_filename) { $form .= Linker::makeKnownLinkObj($titleObj, htmlspecialchars($row->acd_filename), 'file=' . $row->acd_storage_key); } else { $form .= wfMsgHtml('confirmaccount-none-p'); } $form .= "</p><p>" . wfMsgHtml('usercredentials-notes') . "</p>\n"; $form .= "<p><textarea tabindex='1' readonly='readonly' name='wpNotes' id='wpNotes' rows='3' cols='80' style='width:100%'>" . htmlspecialchars($row->acd_notes) . "</textarea></p>\n"; $form .= "<p>" . wfMsgHtml('usercredentials-urls') . "</p>\n"; $form .= ConfirmAccountsPage::parseLinks($row->acd_urls); } if ($reqUser->isAllowed('requestips')) { $form .= "<p>" . wfMsgHtml('usercredentials-ip') . " " . htmlspecialchars($row->acd_ip) . "</p>\n"; } $form .= '</fieldset>'; $out->addHTML($form); }
/** * (a) Try to confirm an email address via a token * (b) Notify $wgConfirmAccountContact on success * @param $code string The token * @return void */ protected function confirmEmailToken($code) { global $wgConfirmAccountContact, $wgPasswordSender, $wgPasswordSenderName; $reqUser = $this->getUser(); $out = $this->getOutput(); # Confirm if this token is in the pending requests $name = ConfirmAccount::requestNameFromEmailToken($code); if ($name !== false) { # Send confirmation email to prospective user ConfirmAccount::confirmEmail($name); # Send mail to admin after e-mail has been confirmed if ($wgConfirmAccountContact != '') { $target = new MailAddress($wgConfirmAccountContact); $source = new MailAddress($wgPasswordSender, $wgPasswordSenderName); $title = SpecialPage::getTitleFor('ConfirmAccounts'); $subject = wfMsgForContent('requestaccount-email-subj-admin'); $body = wfMsgForContent('requestaccount-email-body-admin', $name, $title->getFullUrl()); # Actually send the email... $result = UserMailer::send($target, $source, $subject, $body); if (!$result->isOK()) { wfDebug("Could not sent email to admin at {$target}\n"); } } $out->addWikiMsg('request-account-econf'); $out->returnToMain(); } else { # Maybe the user confirmed after account was created... $user = User::newFromConfirmationCode($code); if (is_object($user)) { if ($user->confirmEmail()) { $message = $reqUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success'; $out->addWikiMsg($message); if (!$reqUser->isLoggedIn()) { $title = SpecialPage::getTitleFor('Userlogin'); $out->returnToMain(true, $title->getPrefixedUrl()); } } else { $out->addWikiMsg('confirmemail_error'); } } else { $out->addWikiMsg('confirmemail_invalid'); } } }
/** * (a) Try to confirm an email address via a token * (b) Notify $wgConfirmAccountContact on success * @param $code string The token * @return void */ protected function confirmEmailToken($code) { global $wgConfirmAccountContact, $wgPasswordSender; $reqUser = $this->getUser(); $out = $this->getOutput(); # Confirm if this token is in the pending requests $name = ConfirmAccount::requestNameFromEmailToken($code); if ($name !== false) { # Send confirmation email to prospective user ConfirmAccount::confirmEmail($name); $adminsNotify = ConfirmAccount::getAdminsToNotify(); # Send an email to admin after email has been confirmed if ($adminsNotify->count() || $wgConfirmAccountContact != '') { $title = SpecialPage::getTitleFor('ConfirmAccounts'); $subject = $this->msg('requestaccount-email-subj-admin')->inContentLanguage()->escaped(); $body = $this->msg('requestaccount-email-body-admin', $name)->rawParams($title->getFullUrl())->inContentLanguage()->escaped(); # Actually send the email... if ($wgConfirmAccountContact != '') { $source = new MailAddress($wgPasswordSender, wfMessage('emailsender')->text()); $target = new MailAddress($wgConfirmAccountContact); $result = UserMailer::send($target, $source, $subject, $body); if (!$result->isOK()) { wfDebug("Could not sent email to admin at {$target}\n"); } } # Send an email to all users with "confirmaccount-notify" rights foreach ($adminsNotify as $adminNotify) { if ($adminNotify->canReceiveEmail()) { $adminNotify->sendMail($subject, $body); } } } $out->addWikiMsg('request-account-econf'); $out->returnToMain(); } else { # Maybe the user confirmed after account was created... $user = User::newFromConfirmationCode($code); if (is_object($user)) { $user->confirmEmail(); $user->saveSettings(); $message = $reqUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success'; $out->addWikiMsg($message); if (!$reqUser->isLoggedIn()) { $title = SpecialPage::getTitleFor('Userlogin'); $out->returnToMain(true, $title); } } else { $out->addWikiMsg('confirmemail_invalid'); } } }