public function execute() { $params = $this->extractRequestParams(); $res = $this->getResult(); $res->addValue(null, $this->getModuleName(), array('username' => $params['username'])); $spoof = new SpoofUser($params['username']); if ($spoof->isLegal()) { $normalized = $spoof->getNormalized(); $res->addValue(null, $this->getModuleName(), array('normalised' => $normalized)); $unfilteredConflicts = $spoof->getConflicts(); if (empty($unfilteredConflicts)) { $res->addValue(null, $this->getModuleName(), array('result' => 'pass')); } else { $hasSuppressed = false; $conflicts = array(); foreach ($unfilteredConflicts as $conflict) { if (!User::newFromName($conflict)->isHidden()) { $conflicts[] = $conflict; } else { $hasSuppressed = true; } } if ($hasSuppressed) { $res->addValue(null, $this->getModuleName(), array('suppressed' => 'true')); } $res->addValue(null, $this->getModuleName(), array('result' => 'conflict')); $res->setIndexedTagName($conflicts, 'u'); $res->addValue(array($this->getModuleName()), 'users', $conflicts); } } else { $error = $spoof->getError(); $res->addValue('antispoof', 'result', 'error'); $res->addValue('antispoof', 'error', $error); } }
/** * Given a username, returns one of several codes to indicate whether it is valid to be a NEW username or not. * * Codes: * - OK: A user with this username may be created. * - INVALID: This is not a valid username. This may mean that it is too long or has characters that aren't permitted, etc. * - EXISTS: A user with this name, so you cannot create one with this name. * * TODO: Is this a duplicate of user::isCreatableName()? It is important to note that wgWikiaMaxNameChars may be less than wgMaxNameChars which * is intentional because there are some long usernames that were created when only wgMaxNameChars limited to 255 characters and we still want * those usernames to be valid (so that they can still login), but we just don't want NEW accounts to be created above the length of wgWikiaMaxNameChars. * * @param string $uName The user name to check * * @return bool|string Return errors as an i18n key or true if the name is valid */ function wfValidateUserName($uName) { if (!User::isNotMaxNameChars($uName)) { return 'userlogin-bad-username-length'; } $userTitle = Title::newFromText($uName); if (is_null($userTitle)) { return 'userlogin-bad-username-character'; } $uName = $userTitle->getText(); if (!User::isCreatableName($uName)) { return 'userlogin-bad-username-character'; } $dbr = wfGetDB(DB_SLAVE); $uName = $dbr->strencode($uName); if ($uName == '') { return 'userlogin-bad-username-character'; } if (class_exists('SpoofUser')) { $spoof = new SpoofUser($uName); if ($spoof->isLegal()) { $conflicts = $spoof->getConflicts(); if (!empty($conflicts)) { return 'userlogin-bad-username-taken'; } } } if (in_array($uName, F::app()->wg->ReservedUsernames)) { // if we returned 'invalid', that would be confusing once a user // checked and found that the name already met the naming requirements. return 'userlogin-bad-username-taken'; } // This username is valid return true; }
/** * @dataProvider providePositives * See http://www.phpunit.de/manual/3.4/en/appendixes.annotations.html#appendixes.annotations.dataProvider */ public function testCheckSpoofing($userName, $spooferName) { $Alice = new SpoofUser($userName); $Eve = new SpoofUser($spooferName); if ($Eve->isLegal()) { $this->assertEquals($Alice->getNormalized(), $Eve->getNormalized(), "Check that '{$spooferName}' can't spoof account '{$userName}'"); } }
/** * @covers SpoofUser::update */ public function testUpdate() { $user = User::newFromName('MyNewUserName'); $user->addToDatabase(); $s = new SpoofUser('MyNewUserName'); $s->update('BAZFOO'); $this->assertArrayEquals(array('MyNewUserName'), $s->getConflicts()); $foobaz = new SpoofUser('BAZFOO'); $this->assertArrayEquals(array('BazF00', 'BazFoo'), $foobaz->getConflicts()); }
/** * AntiSpoof: update records once a new account has been created. * * @see extensions/AntiSpoof */ public function updateAntiSpoof() { $this->response->setFormat('json'); $this->response->setCacheValidity(\WikiaResponse::CACHE_DISABLED); $this->response->setVal('success', false); if ($this->getVal('secret') != $this->wg->TheSchwartzSecretToken) { $this->response->setVal('message', 'invalid secret'); return; } $username = $this->getVal('username'); if (!empty($this->wg->EnableAntiSpoofExt)) { $spoofUser = new \SpoofUser($username); $this->response->setVal('success', $spoofUser->record()); return; } }
/** * remove user from user_temp table * @param integer $fromUserId * @param integer $toUserId * @param integer $range * @param string $condition */ function removeOldTempUser($fromUserId, $toUserId, $range, $condition) { wfProfileIn(__METHOD__); if (wfReadOnly()) { echo "Error: Read Only Mode.\n"; } else { // get scope if (empty($fromUserId) || empty($toUserId)) { getScope($fromUserId, $toUserId, $condition); } // remove old temp user $cnt = 0; do { $to = $toUserId - $fromUserId > $range ? $fromUserId + $range : $toUserId; echo "Removing temp user (UserId {$fromUserId} to {$to})...\n"; $users = getTempUsers($fromUserId, $to, $condition); $cnt = $cnt + count($users); foreach ($users as $username) { $tempUser = TempUser::getTempUserFromName($username); $id = $tempUser->getId(); $tempUser->removeFromDatabase(); // remove spoof normalization record from the database $spoof = new SpoofUser($username); $spoof->removeRecord(); echo "Removed temp user (id={$id}) from database.\n"; } $fromUserId = $to; } while ($fromUserId < $toUserId); echo "Total {$cnt} temp users removed from database.\n"; } wfProfileOut(__METHOD__); }
/** * Checks if the request provided to the constructor is valid. * * @return bool True if all prerequisites are met */ protected function setup() { wfProfileIn(__METHOD__); global $wgContLang, $wgCapitalLinks; //Sanitize input data $oldnamePar = trim(str_replace('_', ' ', $this->mRequestData->oldUsername)); $oldTitle = Title::makeTitle(NS_USER, $oldnamePar); // Force uppercase of newusername, otherwise wikis with wgCapitalLinks=false can create lc usernames $newTitle = Title::makeTitleSafe(NS_USER, $wgContLang->ucfirst($this->mRequestData->newUsername)); $oun = is_object($oldTitle) ? $oldTitle->getText() : ''; $nun = is_object($newTitle) ? $newTitle->getText() : ''; $this->addInternalLog("title: old={$oun} new={$nun}"); //AntiSpoof test if (class_exists('SpoofUser')) { $oNewSpoofUser = new SpoofUser($nun); if (!$oNewSpoofUser->isLegal()) { $this->addWarning(wfMessage('userrenametool-error-antispoof-conflict', $nun)); } } else { $this->addError(wfMessage('userrenametool-error-antispoof-notinstalled')); } //Phalanx test $warning = RenameUserHelper::testBlock($oun); if (!empty($warning)) { $this->addWarning($warning); } $warning = RenameUserHelper::testBlock($nun); if (!empty($warning)) { $this->addWarning($warning); } //Invalid old user name entered if (!$oun) { $this->addError(wfMessage('userrenametool-errorinvalid', $this->mRequestData->oldUsername)->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } //Invalid new user name entered if (!$nun) { $this->addError(wfMessage('userrenametool-errorinvalidnew', $this->mRequestData->newUsername)->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } //Old username is the same as new username if ($oldTitle->getText() === $newTitle->getText()) { $this->addError(wfMessage('userrenametool-error-same-user')->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } //validate new username and disable validation for old username $olduser = User::newFromName($oldTitle->getText(), false); $newuser = User::newFromName($newTitle->getText(), 'creatable'); // It won't be an object if for instance "|" is supplied as a value if (!is_object($olduser)) { $this->addError(wfMessage('userrenametool-errorinvalid', $this->mRequestData->oldUsername)->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } if (!is_object($newuser) || !User::isCreatableName($newuser->getName())) { $this->addError(wfMessage('userrenametool-errorinvalid', $this->mRequestData->newUsername)->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } $this->addInternalLog("user: old={$olduser->getName()}:{$olduser->getId()} new={$newuser->getName()}:{$newuser->getId()}"); // Check for the existence of lowercase oldusername in database. // Until r19631 it was possible to rename a user to a name with first character as lowercase if ($oldTitle->getText() !== $wgContLang->ucfirst($oldTitle->getText())) { // oldusername was entered as lowercase -> check for existence in table 'user' $dbr = WikiFactory::db(DB_SLAVE); $uid = $dbr->selectField('`user`', 'user_id', array('user_name' => $oldTitle->getText()), __METHOD__); $this->addLog('Running query: ' . $dbr->lastQuery() . " resulted in " . $dbr->affectedRows() . " row(s) being affected."); if ($uid === false) { if (!$wgCapitalLinks) { $uid = 0; // We are on a lowercase wiki but lowercase username does not exists } else { // We are on a standard uppercase wiki, use normal $uid = $olduser->idForName(); $oldTitle = Title::makeTitleSafe(NS_USER, $olduser->getName()); } } } else { // oldusername was entered as upperase -> standard procedure $uid = $olduser->idForName(); } $this->addInternalLog("id: uid={$uid} old={$olduser->getName()}:{$olduser->getId()} new={$newuser->getName()}:{$newuser->getId()}"); //If old user name does not exist: if ($uid == 0) { $this->addError(wfMessage('userrenametool-errordoesnotexist', $this->mRequestData->oldUsername)->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } elseif ($olduser->isLocked()) { $this->addError(wfMessage('userrenametool-errorlocked', $this->mRequestData->oldUsername)->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } elseif ($olduser->isAllowed('bot')) { $this->addError(wfMessage('userrenametool-errorbot', $this->mRequestData->oldUsername)->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } $fakeuid = 0; //If new user name does exist (we have a special case - repeating rename process) if ($newuser->idForName() != 0) { $repeating = false; $processing = false; //invalidate properties cache and reload to get updated data //needed here, if the cache is wrong bad things happen $this->addInternalLog("pre-invalidate: titletext={$oldTitle->getText()} old={$olduser->getName()}"); $olduser->invalidateCache(); $olduser = User::newFromName($oldTitle->getText(), false); $renameData = $olduser->getGlobalAttribute('renameData', ''); $this->addInternalLog("post-invalidate: titletext={$oldTitle->getText()} old={$olduser->getName()}:{$olduser->getId()}"); $this->addLog("Scanning user option renameData for process data: {$renameData}"); if (stripos($renameData, self::RENAME_TAG) !== false) { $tokens = explode(';', $renameData, 3); if (!empty($tokens[0])) { $nameTokens = explode('=', $tokens[0], 2); $repeating = count($nameTokens) == 2 && $nameTokens[0] === self::RENAME_TAG && $nameTokens[1] === $newuser->getName(); } if (!empty($tokens[1])) { $statusTokens = explode('=', $tokens[1], 2); $processing = count($statusTokens) == 2 && $statusTokens[0] === self::PROCESS_TAG && (int) $statusTokens[1] === 1; } if (!empty($tokens[2])) { $blockTokens = explode('=', $tokens[2], 2); if (count($blockTokens) == 2 && $blockTokens[0] === self::PHALANX_BLOCK_TAG && is_numeric($blockTokens[1])) { $this->mPhalanxBlockId = (int) $blockTokens[1]; } } } /** * Not needed, process must be resumable even in case of fatal errors, if 2 processes are run nothing bad happens //if the process is already running throw an error if($processing){ $this->addError( wfMessage( 'userrenametool-errorprocessing', $olduser->getName(), $newuser->getName())->inContentLanguage()->text() ); wfProfileOut(__METHOD__); return false; }*/ if ($repeating) { $this->addWarning(wfMessage('userrenametool-warn-repeat', $this->mRequestData->oldUsername, $this->mRequestData->newUsername)->inContentLanguage()->text()); //Swap the uids because the real user ID is the new user ID in this special case $fakeuid = $uid; $uid = $newuser->idForName(); } else { //In the case other than repeating the process drop an error $this->addError(wfMessage('userrenametool-errorexists', $newuser->getName())->inContentLanguage()->text()); wfProfileOut(__METHOD__); return false; } } //Execute Warning hook (arguments the same as in the original Renameuser extension) if (!$this->mActionConfirmed) { wfRunHooks('UserRename::Warning', array($this->mRequestData->oldUsername, $this->mRequestData->newUsername, &$this->mWarnings)); } $this->mOldUsername = $olduser->getName(); $this->mNewUsername = $newuser->getName(); $this->mUserId = (int) $uid; $this->mFakeUserId = $fakeuid; $this->addInternalLog("setup: uid={$this->mUserId} fakeuid={$this->mFakeUserId} old={$this->mOldUsername} new={$this->mNewUsername}"); //If there are only warnings and user confirmed that, do not show them again //on success page ;-) if ($this->mActionConfirmed) { $this->mWarnings = array(); } elseif (count($this->mWarnings)) { //in case action is not confirmed and there are warnings display them and wait for confirmation before running the process wfProfileOut(__METHOD__); return false; } wfProfileOut(__METHOD__); return empty($this->mErrors); }
<?php // Go through all usernames and calculate and record spoof thingies $base = dirname(dirname(dirname(__FILE__))); require $base . '/maintenance/commandLine.inc'; $dbw = wfGetDB(DB_MASTER); $dbw->bufferResults(false); $batchSize = 1000; $result = $dbw->select('user', 'user_name', null, 'batchAntiSpoof.php'); $n = 0; while ($row = $dbw->fetchObject($result)) { if ($n++ % $batchSize == 0) { echo "{$wgDBname} {$n}\n"; } $items[] = new SpoofUser($row->user_name); if ($n % $batchSize == 0) { SpoofUser::batchRecord($items); $items = array(); } } SpoofUser::batchRecord($items); echo "{$wgDBname} {$n} done.\n"; $dbw->freeResult($result);
/** * @param $items array */ protected function batchRecord($items) { SpoofUser::batchRecord($items); }
public static function asDeleteAccount(User &$oldUser) { $spoof = new SpoofUser($oldUser->getName()); $spoof->remove(); return true; }
/** * On new account creation, record the username's thing-bob. */ function asAddNewAccountHook($user) { $spoof = new SpoofUser($user->getName()); $spoof->record(); return true; }
/** * @param $items array */ protected function batchRecord($items) { SpoofUser::batchRecord($this->getDB(DB_MASTER), $items); }