r98849 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r98848‎ | r98849 | r98850 >
Date:03:41, 4 October 2011
Author:aaron
Status:deferred (Comments)
Tags:
Comment:
* Refactored out acquireUsername and acquireEmail functions. These also use locking.
* Moved some of the heaver checks in AccountRequestSubmission::submit() down a bit.
* Avoid using inexistent 'uploadcorrupt' message.
* Delete uploaded file on rollback.
* Fixed bogus $name and $ip var uses.
Modified paths:
  • /trunk/extensions/ConfirmAccount/business/AccountRequestSubmission.php (modified) (history)
  • /trunk/extensions/ConfirmAccount/dataclasses/UserAccountRequest.php (modified) (history)
  • /trunk/extensions/ConfirmAccount/presentation/specialpages/actions/RequestAccount_body.php (modified) (history)

Diff [purge]

Index: trunk/extensions/ConfirmAccount/dataclasses/UserAccountRequest.php
@@ -248,6 +248,7 @@
249249 }
250250
251251 /**
 252+ * Try to insert the request into the database
252253 * @return int
253254 */
254255 public function insertOn() {
@@ -303,6 +304,34 @@
304305 }
305306
306307 /**
 308+ * Try to acquire a username in the request queue for insertion
 309+ * @return bool
 310+ */
 311+ public static function acquireUsername( $name ) {
 312+ $dbw = wfGetDB( DB_MASTER );
 313+ $conds = array( 'acr_name' => $name );
 314+ if ( $dbw->selectField( 'account_requests', '1', $conds, __METHOD__ ) ) {
 315+ return false; // already in use
 316+ }
 317+ return !$dbw->selectField( 'account_requests', '1',
 318+ $conds, __METHOD__, array( 'FOR UPDATE' ) ); // acquire LOCK
 319+ }
 320+
 321+ /**
 322+ * Try to acquire a e-mail address in the request queue for insertion
 323+ * @return bool
 324+ */
 325+ public static function acquireEmail( $email ) {
 326+ $dbw = wfGetDB( DB_MASTER );
 327+ $conds = array( 'acr_email' => $email );
 328+ if ( $dbw->selectField( 'account_requests', '1', $conds, __METHOD__ ) ) {
 329+ return false; // already in use
 330+ }
 331+ return !$dbw->selectField( 'account_requests', '1',
 332+ $conds, __METHOD__, array( 'FOR UPDATE' ) ); // acquire LOCK
 333+ }
 334+
 335+ /**
307336 * Flatten areas of interest array
308337 * Used by ConfirmAccountsPage
309338 * @param $areas Array
Index: trunk/extensions/ConfirmAccount/business/AccountRequestSubmission.php
@@ -60,13 +60,14 @@
6161 */
6262 public function submit( IContextSource $context ) {
6363 global $wgAuth, $wgAccountRequestThrottle, $wgMemc, $wgContLang;
 64+ global $wgAccountRequestToS, $wgAccountRequestMinWords;
6465 $reqUser = $this->requester;
6566
6667 # Now create a dummy user ($u) and check if it is valid
6768 if ( $this->userName === '' ) {
6869 return array( 'accountreq_no_name', wfMsgHtml( 'noname' ) );
6970 }
70 - $u = User::newFromName( $name, 'creatable' );
 71+ $u = User::newFromName( $this->userName, 'creatable' );
7172 if ( !$u ) {
7273 return array( 'accountreq_invalid_name', wfMsgHtml( 'noname' ) );
7374 }
@@ -80,19 +81,7 @@
8182 );
8283 }
8384 }
84 - # Check if already in use
85 - if ( 0 != $u->idForName() || $wgAuth->userExists( $u->getName() ) ) {
86 - return array( 'accountreq_username_exists', wfMsgHtml( 'userexists' ) );
87 - }
88 - # Check pending accounts for name use
89 - $dbw = wfGetDB( DB_MASTER );
90 - $dup = $dbw->selectField( 'account_requests', '1',
91 - array( 'acr_name' => $u->getName() ), __METHOD__ );
92 - if ( $dup ) {
93 - return array( 'accountreq_username_pending', wfMsgHtml( 'requestaccount-inuse' ) );
94 - }
9585 # Make sure user agrees to policy here
96 - global $wgAccountRequestToS;
9786 if ( $wgAccountRequestToS && !$this->tosAccepted ) {
9887 return array( 'acct_request_skipped_tos', wfMsgHtml( 'requestaccount-agree' ) );
9988 }
@@ -101,23 +90,12 @@
10291 return array( 'acct_request_invalid_email', wfMsgHtml( 'invalidemailaddress' ) );
10392 }
10493 # Check if biography is long enough
105 - global $wgAccountRequestMinWords;
10694 if ( str_word_count( $this->bio ) < $wgAccountRequestMinWords ) {
10795 return array( 'acct_request_short_bio',
10896 wfMsgExt( 'requestaccount-tooshort', 'parsemag',
10997 $wgContLang->formatNum( $wgAccountRequestMinWords ) )
11098 );
11199 }
112 - # Set some additional data so the AbortNewAccount hook can be
113 - # used for more than just username validation
114 - $u->setEmail( $this->email );
115 - # Check if someone else has an account request with the same email
116 - $dup = $dbw->selectField( 'account_requests', '1',
117 - array( 'acr_email' => $u->getEmail() ), __METHOD__ );
118 - if ( $dup ) {
119 - return array( 'acct_request_email_exists', wfMsgHtml( 'requestaccount-emaildup' ) );
120 - }
121 - $u->setRealName( $this->realName );
122100 # Per security reasons, file dir cannot be pulled from client,
123101 # so ask them to resubmit it then...
124102 global $wgAllowAccountRequestFiles, $wgAccountRequestExtraInfo;
@@ -133,35 +111,63 @@
134112 return array( false, wfMsgHtml( 'requestaccount-resub' ) );
135113 }
136114 }
 115+ # Check if already in use
 116+ if ( 0 != $u->idForName() || $wgAuth->userExists( $u->getName() ) ) {
 117+ return array( 'accountreq_username_exists', wfMsgHtml( 'userexists' ) );
 118+ }
 119+ # Set email and real name
 120+ $u->setEmail( $this->email );
 121+ $u->setRealName( $this->realName );
 122+
 123+ $dbw = wfGetDB( DB_MASTER );
 124+ $dbw->begin(); // ready to acquire locks
 125+ # Check pending accounts for name use
 126+ if ( !UserAccountRequest::acquireUsername( $u->getName() ) ) {
 127+ $dbw->rollback();
 128+ return array( 'accountreq_username_pending', wfMsgHtml( 'requestaccount-inuse' ) );
 129+ }
 130+ # Check if someone else has an account request with the same email
 131+ if ( !UserAccountRequest::acquireEmail( $u->getEmail() ) ) {
 132+ $dbw->rollback();
 133+ return array( 'acct_request_email_exists', wfMsgHtml( 'requestaccount-emaildup' ) );
 134+ }
137135 # Process upload...
138136 if ( $allowFiles && $this->attachmentSrcName ) {
 137+ global $wgAccountRequestExts, $wgConfirmAccountFSRepos;
 138+
139139 $ext = explode( '.', $this->attachmentSrcName );
140140 $finalExt = $ext[count( $ext ) - 1];
141141 # File must have size.
142142 if ( trim( $this->attachmentSrcName ) == '' || empty( $this->attachmentSize ) ) {
143143 $this->attachmentPrevName = '';
 144+ $dbw->rollback();
144145 return array( 'acct_request_empty_file', wfMsgHtml( 'emptyfile' ) );
145146 }
146147 # Look at the contents of the file; if we can recognize the
147 - # type but it's corrupt or data of the wrong type, we should
148 - # probably not accept it.
149 - global $wgAccountRequestExts;
150 - if ( !in_array( $finalExt, $wgAccountRequestExts ) ) {
151 - $this->attachmentPrevName = '';
 148+ # type but it's corrupt or data of the wrong type, we should
 149+ # probably not accept it.
 150+ if ( !in_array( $finalExt, $wgAccountRequestExts ) ) {
 151+ $this->attachmentPrevName = '';
 152+ $dbw->rollback();
152153 return array( 'acct_request_bad_file_ext', wfMsgHtml( 'requestaccount-exts' ) );
153 - }
 154+ }
154155 $veri = ConfirmAccount::verifyAttachment( $this->attachmentTempPath, $finalExt );
155156 if ( !$veri->isGood() ) {
156157 $this->attachmentPrevName = '';
157 - return array( 'acct_request_corrupt_file', wfMsgHtml( 'uploadcorrupt' ) );
 158+ $dbw->rollback();
 159+ return array( 'acct_request_corrupt_file', wfMsgHtml( 'verification-error' ) );
158160 }
159161 # Start a transaction, move file from temp to account request directory.
160 - global $wgConfirmAccountFSRepos;
161162 $repo = new FSRepo( $wgConfirmAccountFSRepos['accountreqs'] );
162163 $key = sha1_file( $this->attachmentTempPath ) . '.' . $finalExt;
163164 $pathRel = $key[0].'/'.$key[0].$key[1].'/'.$key[0].$key[1].$key[2].'/'.$key;
164165 $triplet = array( $this->attachmentTempPath, 'public', $pathRel );
165 - $repo->storeBatch( array($triplet) ); // save!
 166+ $status = $repo->storeBatch( array( $triplet ), FSRepo::OVERWRITE_SAME ); // save!
 167+ if ( !$status->isOk() ) {
 168+ $dbw->rollback();
 169+ return array( 'acct_request_file_store_error',
 170+ wfMsgHtml( 'filecopyerror', $this->attachmentTempPath, $pathRel ) );
 171+ }
166172 }
167173 $expires = null; // passed by reference
168174 $token = ConfirmAccount::getConfirmationToken( $u, $expires );
@@ -186,24 +192,26 @@
187193 'email_token_expires' => $expires,
188194 'ip' => $this->ip,
189195 ) );
190 - $dbw->begin();
191196 $req->insertOn();
192197 # Send confirmation, required!
193 - $result = ConfirmAccount::sendConfirmationMail( $u, $ip, $token, $expires );
 198+ $result = ConfirmAccount::sendConfirmationMail( $u, $this->ip, $token, $expires );
194199 if ( !$result->isOK() ) {
195 - $dbw->rollback(); // Nevermind
 200+ $dbw->rollback(); // nevermind
 201+ if ( isset( $repo ) && isset( $pathRel ) ) { // remove attachment
 202+ $repo->cleanupBatch( array( array( 'public', $pathRel ) ) );
 203+ }
196204 return array( 'acct_request_mail_failed',
197205 wfMsg( 'mailerror', $context->getOutput()->parse( $result->getWikiText() ) ) );
198206 }
199207 $dbw->commit();
 208+
200209 # Clear cache for notice of how many account requests there are
201210 $key = wfMemcKey( 'confirmaccount', 'noticecount' );
202211 $wgMemc->delete( $key );
203212 # No request spamming...
204 - # BC: check if isPingLimitable() exists
205213 if ( $wgAccountRequestThrottle && $reqUser->isPingLimitable() ) {
206214 $key = wfMemcKey( 'acctrequest', 'ip', $ip );
207 - $value = $wgMemc->incr( $key );
 215+ $value = $wgMemc->incr( $key );
208216 if ( !$value ) {
209217 $wgMemc->set( $key, 1, 86400 );
210218 }
Index: trunk/extensions/ConfirmAccount/presentation/specialpages/actions/RequestAccount_body.php
@@ -236,6 +236,10 @@
237237 $this->showForm( wfMsgHtml( 'noname' ) );
238238 return;
239239 }
 240+ # Set some additional data so the AbortNewAccount hook can be
 241+ # used for more than just username validation
 242+ $u->setEmail( $this->mEmail );
 243+ $u->setRealName( $this->mRealName );
240244 # FIXME: Hack! If we don't want captchas for requests, temporarily turn it off!
241245 global $wgConfirmAccountCaptchas, $wgCaptchaTriggers;
242246 if ( !$wgConfirmAccountCaptchas && isset( $wgCaptchaTriggers ) ) {
@@ -340,23 +344,23 @@
341345 }
342346 $out->addWikiMsg( 'request-account-econf' );
343347 $out->returnToMain();
344 - return;
345 - }
346 - # Maybe the user confirmed after account was created...
347 - $user = User::newFromConfirmationCode( $code );
348 - if ( is_object( $user ) ) {
349 - if ( $user->confirmEmail() ) {
350 - $message = $reqUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
351 - $out->addWikiMsg( $message );
352 - if ( !$reqUser->isLoggedIn() ) {
353 - $title = SpecialPage::getTitleFor( 'Userlogin' );
354 - $out->returnToMain( true, $title->getPrefixedUrl() );
 348+ } else {
 349+ # Maybe the user confirmed after account was created...
 350+ $user = User::newFromConfirmationCode( $code );
 351+ if ( is_object( $user ) ) {
 352+ if ( $user->confirmEmail() ) {
 353+ $message = $reqUser->isLoggedIn() ? 'confirmemail_loggedin' : 'confirmemail_success';
 354+ $out->addWikiMsg( $message );
 355+ if ( !$reqUser->isLoggedIn() ) {
 356+ $title = SpecialPage::getTitleFor( 'Userlogin' );
 357+ $out->returnToMain( true, $title->getPrefixedUrl() );
 358+ }
 359+ } else {
 360+ $out->addWikiMsg( 'confirmemail_error' );
355361 }
356362 } else {
357 - $out->addWikiMsg( 'confirmemail_error' );
 363+ $out->addWikiMsg( 'confirmemail_invalid' );
358364 }
359 - } else {
360 - $out->addWikiMsg( 'confirmemail_invalid' );
361365 }
362366 }
363367 }

Comments

#Comment by Aaron Schulz (talk | contribs)   03:47, 4 October 2011

Also moved comment about AbortNewAccount and made it actually hold true.

Status & tagging log