function show() { $out = $this->getOutput(); $user = $this->getUser(); // Header $out->addWikiMsg('abusefilter-tools-text'); // Expression evaluator $eval = ''; $eval .= AbuseFilter::buildEditBox('', 'wpTestExpr'); // Only let users with permission actually test it if ($user->isAllowed('abusefilter-modify')) { $eval .= Xml::tags('p', null, Xml::element('input', array('type' => 'button', 'id' => 'mw-abusefilter-submitexpr', 'value' => $this->msg('abusefilter-tools-submitexpr')->text()))); $eval .= Xml::element('p', array('id' => 'mw-abusefilter-expr-result'), ' '); } $eval = Xml::fieldset($this->msg('abusefilter-tools-expr')->text(), $eval); $out->addHTML($eval); $out->addModules('ext.abuseFilter.tools'); if ($user->isAllowed('abusefilter-modify')) { // Hacky little box to re-enable autoconfirmed if it got disabled $rac = ''; $rac .= Xml::inputLabel($this->msg('abusefilter-tools-reautoconfirm-user')->text(), 'wpReAutoconfirmUser', 'reautoconfirm-user', 45); $rac .= ' '; $rac .= Xml::element('input', array('type' => 'button', 'id' => 'mw-abusefilter-reautoconfirmsubmit', 'value' => $this->msg('abusefilter-tools-reautoconfirm-submit')->text())); $rac = Xml::fieldset($this->msg('abusefilter-tools-reautoconfirm')->text(), $rac); $out->addHTML($rac); } }
function show() { global $wgOut, $wgUser; // Header $wgOut->setSubTitle(wfMsg('abusefilter-tools-subtitle')); $wgOut->addWikiMsg('abusefilter-tools-text'); // Expression evaluator $eval = ''; $eval .= AbuseFilter::buildEditBox('', 'wpTestExpr'); // Only let users with permission actually test it if ($wgUser->isAllowed('abusefilter-modify')) { $eval .= Xml::tags('p', null, Xml::element('input', array('type' => 'button', 'id' => 'mw-abusefilter-submitexpr', 'onclick' => 'doExprSubmit();', 'value' => wfMsg('abusefilter-tools-submitexpr')))); $eval .= Xml::element('p', array('id' => 'mw-abusefilter-expr-result'), ' '); } $eval = Xml::fieldset(wfMsg('abusefilter-tools-expr'), $eval); $wgOut->addHTML($eval); // Associated script $exprScript = file_get_contents(dirname(__FILE__) . '/tools.js'); $wgOut->addInlineScript($exprScript); global $wgUser; if ($wgUser->isAllowed('abusefilter-modify')) { // Hacky little box to re-enable autoconfirmed if it got disabled $rac = ''; $rac .= Xml::inputLabel(wfMsg('abusefilter-tools-reautoconfirm-user'), 'wpReAutoconfirmUser', 'reautoconfirm-user', 45); $rac .= ' '; $rac .= Xml::element('input', array('type' => 'button', 'id' => 'mw-abusefilter-reautoconfirmsubmit', 'onclick' => 'doReautoSubmit();', 'value' => wfMsg('abusefilter-tools-reautoconfirm-submit'))); $rac = Xml::fieldset(wfMsg('abusefilter-tools-reautoconfirm'), $rac); $wgOut->addHTML($rac); } }
public function execute() { $params = $this->extractRequestParams(); $this->requireOnlyOneParameter($params, 'vars', 'rcid', 'logid'); // "Anti-DoS" if (!$this->getUser()->isAllowed('abusefilter-modify')) { $this->dieUsageMsg('permissiondenied'); } if ($params['vars']) { $vars = FormatJson::decode($params['vars'], true); } elseif ($params['rcid']) { $dbr = wfGetDB(DB_SLAVE); $row = $dbr->selectRow('recentchanges', '*', array('rc_id' => $params['rcid']), __METHOD__); if (!$row) { $this->dieUsageMsg(array('nosuchrcid', $params['rcid'])); } $vars = AbuseFilter::getVarsFromRCRow($row); } elseif ($params['logid']) { $dbr = wfGetDB(DB_SLAVE); $row = $dbr->selectRow('abuse_filter_log', '*', array('afl_id' => $params['logid']), __METHOD__); if (!$row) { $this->dieUsage("There is no abuselog entry with the id ``{$params['logid']}''", 'nosuchlogid'); } $vars = AbuseFilter::loadVarDump($row->afl_var_dump); } if (AbuseFilter::checkSyntax($params['filter']) !== true) { $this->dieUsage('The filter has invalid syntax', 'badsyntax'); } $result = AbuseFilter::checkConditions($params['filter'], $vars); $this->getResult()->addValue(null, $this->getModuleName(), array('result' => $result)); }
/** * @return array */ protected function getMessageParameters() { $entry = $this->entry->getParameters(); $params = parent::getMessageParameters(); $filter_title = SpecialPage::getTitleFor('AbuseFilter', $entry['filter']); $filter_caption = $this->msg('abusefilter-log-detailedentry-local')->params($entry['filter']); $log_title = SpecialPage::getTitleFor('AbuseLog', $entry['log']); $log_caption = $this->msg('abusefilter-log-detailslink'); $params[4] = $entry['action']; if ($this->plaintext) { $params[3] = '[[' . $filter_title->getPrefixedText() . '|' . $filter_caption . ']]'; $params[8] = '[[' . $log_title->getPrefixedText() . '|' . $log_caption . ']]'; } else { $params[3] = Message::rawParam(Linker::link($filter_title, htmlspecialchars($filter_caption))); $params[8] = Message::rawParam(Linker::link($log_title, htmlspecialchars($log_caption))); } $actions_taken = $entry['actions']; if (!strlen(trim($actions_taken))) { $actions_taken = $this->msg('abusefilter-log-noactions'); } else { $actions = explode(',', $actions_taken); $displayActions = array(); foreach ($actions as $action) { $displayActions[] = AbuseFilter::getActionDisplay($action); } $actions_taken = $this->context->getLanguage()->commaList($displayActions); } $params[5] = $actions_taken; // Bad things happen if the numbers are not in correct order ksort($params); return $params; }
function doTest() { // Quick syntax check. $out = $this->getOutput(); $result = AbuseFilter::checkSyntax($this->mFilter); if ($result !== true) { $out->addWikiMsg('abusefilter-test-syntaxerr'); return; } $dbr = wfGetDB(DB_SLAVE); $conds = array('rc_user_text' => $this->mTestUser, 'rc_type != ' . RC_EXTERNAL); if ($this->mTestPeriodStart) { $conds[] = 'rc_timestamp >= ' . $dbr->addQuotes($dbr->timestamp(strtotime($this->mTestPeriodStart))); } if ($this->mTestPeriodEnd) { $conds[] = 'rc_timestamp <= ' . $dbr->addQuotes($dbr->timestamp(strtotime($this->mTestPeriodEnd))); } if ($this->mTestPage) { $title = Title::newFromText($this->mTestPage); if ($title instanceof Title) { $conds['rc_namespace'] = $title->getNamespace(); $conds['rc_title'] = $title->getDBkey(); } else { $out->addWikiMsg('abusefilter-test-badtitle'); return; } } // Get our ChangesList $changesList = new AbuseFilterChangesList($this->getSkin()); $output = $changesList->beginRecentChangesList(); $res = $dbr->select('recentchanges', '*', array_filter($conds), __METHOD__, array('LIMIT' => self::$mChangeLimit, 'ORDER BY' => 'rc_timestamp desc')); $counter = 1; foreach ($res as $row) { $vars = AbuseFilter::getVarsFromRCRow($row); if (!$vars) { continue; } $result = AbuseFilter::checkConditions($this->mFilter, $vars); if ($result || $this->mShowNegative) { // Stash result in RC item $rc = RecentChange::newFromRow($row); $rc->examineParams['testfilter'] = $this->mFilter; $rc->filterResult = $result; $rc->counter = $counter++; $output .= $changesList->recentChangesLine($rc, false); } } $output .= $changesList->endRecentChangesList(); $out->addHTML($output); }
public function execute() { // "Anti-DoS" if (!$this->getUser()->isAllowed('abusefilter-modify')) { $this->dieUsage('You don\'t have permission to check syntax of abuse filters', 'permissiondenied'); } $params = $this->extractRequestParams(); $result = AbuseFilter::checkSyntax($params['filter']); $r = array(); if ($result === true) { // Everything went better than expected :) $r['status'] = 'ok'; } else { $r = array('status' => 'error', 'message' => $result[0], 'character' => $result[1]); } $this->getResult()->addValue(null, $this->getModuleName(), $r); }
public function execute() { if (!$this->getUser()->isAllowed('abusefilter-modify')) { $this->dieUsage('You do not have permissions to unblock autopromotion', 'permissiondenied'); } $params = $this->extractRequestParams(); $user = User::newFromName($params['user']); if ($user === false) { // Oh god this is so bad but this message uses GENDER $msg = wfMessage('abusefilter-reautoconfirm-none', $params['user'])->text(); $this->dieUsage($msg, 'notsuspended'); } global $wgMemc; $key = AbuseFilter::autoPromoteBlockKey($user); if (!$wgMemc->get($key)) { // Same as above :( $msg = wfMessage('abusefilter-reautoconfirm-none', $params['user'])->text(); $this->dieUsage($msg, 'notsuspended'); } $wgMemc->delete($key); $res = array('user' => $params['user']); $this->getResult()->addValue(null, $this->getModuleName(), $res); }
protected function setUserVariable($name, $value) { $builderValues = AbuseFilter::getBuilderValues(); if (array_key_exists($name, $builderValues['vars'])) { throw new AFPUserVisibleException('overridebuiltin', $this->mCur->pos, array($name)); } $this->mVars->setVar($name, $value); }
public function execute() { global $wgUser; if (!$wgUser->isAllowed('abusefilter-log')) { $this->dieUsage('You don\'t have permission to view the abuse log', 'permissiondenied'); } $params = $this->extractRequestParams(); $prop = array_flip($params['prop']); $fld_ids = isset($prop['ids']); $fld_filter = isset($prop['filter']); $fld_user = isset($prop['user']); $fld_ip = isset($prop['ip']); $fld_title = isset($prop['title']); $fld_action = isset($prop['action']); $fld_details = isset($prop['details']); $fld_result = isset($prop['result']); $fld_timestamp = isset($prop['timestamp']); $fld_hidden = isset($prop['hidden']); if ($fld_ip && !$wgUser->isAllowed('abusefilter-private')) { $this->dieUsage('You don\'t have permission to view IP addresses', 'permissiondenied'); } if ($fld_details && !$wgUser->isAllowed('abusefilter-log-detail')) { $this->dieUsage('You don\'t have permission to view detailed abuse log entries', 'permissiondenied'); } $result = $this->getResult(); $this->addTables('abuse_filter_log'); $this->addFields('afl_timestamp'); $this->addFieldsIf(array('afl_id', 'afl_filter'), $fld_ids); $this->addFieldsIf('afl_user_text', $fld_user); $this->addFieldsIf('afl_ip', $fld_ip); $this->addFieldsIf(array('afl_namespace', 'afl_title'), $fld_title); $this->addFieldsIf('afl_action', $fld_action); $this->addFieldsIf('afl_var_dump', $fld_details); $this->addFieldsIf('afl_actions', $fld_result); $this->addFieldsIf('afl_deleted', $fld_hidden); if ($fld_filter) { $this->addTables('abuse_filter'); $this->addFields('af_public_comments'); $this->addJoinConds(array('abuse_filter' => array('LEFT JOIN', 'af_id=afl_filter'))); } $this->addOption('LIMIT', $params['limit'] + 1); $this->addWhereRange('afl_timestamp', $params['dir'], $params['start'], $params['end']); $db = $this->getDB(); $notDeletedCond = SpecialAbuseLog::getNotDeletedCond($db); $this->addWhereIf(array('afl_user_text' => $params['user']), isset($params['user'])); $this->addWhereIf(array('afl_filter' => $params['filter']), isset($params['filter'])); $this->addWhereIf($notDeletedCond, !SpecialAbuseLog::canSeeHidden()); $title = $params['title']; if (!is_null($title)) { $titleObj = Title::newFromText($title); if (is_null($titleObj)) { $this->dieUsageMsg(array('invalidtitle', $title)); } $this->addWhereFld('afl_namespace', $titleObj->getNamespace()); $this->addWhereFld('afl_title', $titleObj->getDBkey()); } $res = $this->select(__METHOD__); $count = 0; foreach ($res as $row) { if (++$count > $params['limit']) { // We've had enough $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->afl_timestamp)); break; } $entry = array(); if ($fld_ids) { $entry['id'] = intval($row->afl_id); $entry['filter_id'] = intval($row->afl_filter); } if ($fld_filter) { $entry['filter'] = $row->af_public_comments; } if ($fld_user) { $entry['user'] = $row->afl_user_text; } if ($fld_ip) { $entry['ip'] = $row->afl_ip; } if ($fld_title) { $title = Title::makeTitle($row->afl_namespace, $row->afl_title); ApiQueryBase::addTitleInfo($entry, $title); } if ($fld_action) { $entry['action'] = $row->afl_action; } if ($fld_result) { $entry['result'] = $row->afl_actions; } if ($fld_timestamp) { $entry['timestamp'] = wfTimestamp(TS_ISO_8601, $row->afl_timestamp); } if ($fld_details) { $vars = AbuseFilter::loadVarDump($row->afl_var_dump); if ($vars instanceof AbuseFilterVariableHolder) { $entry['details'] = $vars->exportAllVars(); } else { $entry['details'] = array_change_key_case($vars, CASE_LOWER); } } if ($fld_hidden) { $entry['hidden'] = $row->afl_deleted; } if ($entry) { $fit = $result->addValue(array('query', $this->getModuleName()), null, $entry); if (!$fit) { $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->afl_timestamp)); break; } } } $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'item'); }
/** * Handler for the UploadVerifyFile hook * * @param $upload UploadBase * @param $mime * @param $error array * * @return bool */ public static function onUploadVerifyFile($upload, $mime, &$error) { global $wgUser, $wgVersion; $vars = new AbuseFilterVariableHolder(); $title = $upload->getTitle(); if (!$title) { // If there's no valid title assigned to the upload // it wont proceed anyway, so no point in filtering it. return true; } $vars->addHolders(AbuseFilter::generateUserVars($wgUser), AbuseFilter::generateTitleVars($title, 'FILE')); $vars->setVar('ACTION', 'upload'); // We us the hexadecimal version of the file sha1 if (version_compare($wgVersion, '1.21', '>=')) { // Use UploadBase::getTempFileSha1Base36 so that we don't have to calculate the sha1 sum again $sha1 = wfBaseConvert($upload->getTempFileSha1Base36(), 36, 16, 40); } else { // UploadBase::getTempFileSha1Base36 wasn't public until 1.21 $sha1 = sha1_file($upload->getTempPath()); } $vars->setVar('file_sha1', $sha1); $filter_result = AbuseFilter::filterAction($vars, $title); if (!$filter_result->isOK()) { $error = $filter_result->getErrorsArray(); $error = $error[0]; } return $filter_result->isOK(); }
function formatValue($name, $value) { global $wgOut, $wgLang; static $sk = null; if (empty($sk)) { global $wgUser; $sk = $wgUser->getSkin(); } $row = $this->mCurrentRow; switch ($name) { case 'af_id': return $sk->link(SpecialPage::getTitleFor('AbuseFilter', intval($value)), intval($value)); case 'af_public_comments': return $sk->link(SpecialPage::getTitleFor('AbuseFilter', intval($row->af_id)), $wgOut->parseInline($value)); case 'af_actions': $actions = explode(',', $value); $displayActions = array(); foreach ($actions as $action) { $displayActions[] = AbuseFilter::getActionDisplay($action); } return htmlspecialchars($wgLang->commaList($displayActions)); case 'af_enabled': $statuses = array(); if ($row->af_deleted) { $statuses[] = wfMsgExt('abusefilter-deleted', 'parseinline'); } elseif ($row->af_enabled) { $statuses[] = wfMsgExt('abusefilter-enabled', 'parseinline'); } else { $statuses[] = wfMsgExt('abusefilter-disabled', 'parseinline'); } global $wgAbuseFilterIsCentral; if ($row->af_global && $wgAbuseFilterIsCentral) { $statuses[] = wfMsgExt('abusefilter-status-global', 'parseinline'); } return $wgLang->commaList($statuses); case 'af_hidden': $msg = $value ? 'abusefilter-hidden' : 'abusefilter-unhidden'; return wfMsgExt($msg, 'parseinline'); case 'af_hit_count': $count_display = wfMsgExt('abusefilter-hitcount', array('parseinline'), $wgLang->formatNum($value)); $link = $sk->makeKnownLinkObj(SpecialPage::getTitleFor('AbuseLog'), $count_display, 'wpSearchFilter=' . $row->af_id); return $link; case 'af_timestamp': $userLink = $sk->userLink($row->af_user, $row->af_user_text) . $sk->userToolLinks($row->af_user, $row->af_user_text); $user = $row->af_user_text; return wfMsgExt('abusefilter-edit-lastmod-text', array('replaceafter', 'parseinline'), array($wgLang->timeanddate($value, true), $userLink, $wgLang->date($value, true), $wgLang->time($value, true), $user)); default: throw new MWException("Unknown row type {$name}!"); } }
/** * @param $action * @param $parameters * @return String */ static function formatAction($action, $parameters) { /** @var $wgLang Language */ global $wgLang; if (count($parameters) == 0) { $displayAction = AbuseFilter::getActionDisplay($action); } else { $displayAction = AbuseFilter::getActionDisplay($action) . wfMessage('colon-separator')->escaped() . $wgLang->semicolonList($parameters); } return $displayAction; }
function formatValue($name, $value) { global $wgOut, $wgLang; static $sk = null; if (empty($sk)) { global $wgUser; $sk = $wgUser->getSkin(); } $row = $this->mCurrentRow; $formatted = ''; switch ($name) { case 'afh_timestamp': $title = SpecialPage::getTitleFor('AbuseFilter', 'history/' . $row->afh_filter . '/item/' . $row->afh_id); $formatted = $sk->link($title, $wgLang->timeanddate($row->afh_timestamp, true)); break; case 'afh_user_text': $formatted = $sk->userLink($row->afh_user, $row->afh_user_text) . ' ' . $sk->userToolLinks($row->afh_user, $row->afh_user_text); break; case 'afh_public_comments': $formatted = $wgOut->parse($value); break; case 'afh_flags': $formatted = AbuseFilter::formatFlags($value); break; case 'afh_actions': $actions = unserialize($value); $display_actions = ''; foreach ($actions as $action => $parameters) { $displayAction = AbuseFilter::formatAction($action, $parameters); $display_actions .= Xml::tags('li', null, $displayAction); } $display_actions = Xml::tags('ul', null, $display_actions); $formatted = $display_actions; break; case 'afh_filter': $title = $this->mPage->getTitle(strval($value)); $formatted = $sk->link($title, $value); break; case 'afh_id': $title = $this->mPage->getTitle('history/' . $row->afh_filter . "/diff/prev/{$value}"); $formatted = $sk->link($title, wfMsgExt('abusefilter-history-diff', 'parseinline')); break; default: $formatted = "Unable to format {$name}"; break; } $mappings = array_flip(AbuseFilter::$history_mappings) + array('afh_actions' => 'actions', 'afh_id' => 'id'); $changed = explode(',', $row->afh_changed_fields); $fieldChanged = false; if ($name == 'afh_flags') { // This is a bit freaky, but it works. // Basically, returns true if any of those filters are in the $changed array. $filters = array('af_enabled', 'af_hidden', 'af_deleted', 'af_global'); if (count(array_diff($filters, $changed)) < count($filters)) { $fieldChanged = true; } } elseif (in_array($mappings[$name], $changed)) { $fieldChanged = true; } if ($fieldChanged) { $formatted = Xml::tags('div', array('class' => 'mw-abusefilter-history-changed'), $formatted); } return $formatted; }
function formatValue($name, $value) { $lang = $this->getLanguage(); $row = $this->mCurrentRow; switch ($name) { case 'af_id': return $lang->formatNum(intval($value)); case 'af_public_comments': return $this->getOutput()->parseInline($value); case 'af_actions': $actions = explode(',', $value); $displayActions = array(); foreach ($actions as $action) { $displayActions[] = AbuseFilter::getActionDisplay($action); } return htmlspecialchars($lang->commaList($displayActions)); case 'af_enabled': $statuses = array(); if ($row->af_deleted) { $statuses[] = $this->msg('abusefilter-deleted')->parse(); } elseif ($row->af_enabled) { $statuses[] = $this->msg('abusefilter-enabled')->parse(); } else { $statuses[] = $this->msg('abusefilter-disabled')->parse(); } if ($row->af_global) { $statuses[] = $this->msg('abusefilter-status-global')->parse(); } return $lang->commaList($statuses); case 'af_hidden': $msg = $value ? 'abusefilter-hidden' : 'abusefilter-unhidden'; return $this->msg($msg, 'parseinline')->parse(); case 'af_hit_count': // If the rule is hidden, don't show it, even to priviledged local admins if ($row->af_hidden) { return ''; } return $this->msg('abusefilter-hitcount')->numParams($value)->parse(); case 'af_timestamp': $user = $row->af_user_text; return $this->msg('abusefilter-edit-lastmod-text', $lang->timeanddate($value, true), $user, $lang->date($value, true), $lang->time($value, true), $user)->parse(); case 'af_group': // If this is global, local name probably doesn't exist, but try return AbuseFilter::nameGroup($value); break; default: throw new MWException("Unknown row type {$name}!"); } }
/** * @param $vars AbuseFilterVariableHolder * @return AFPData|array|int|mixed|null|string * @throws MWException * @throws AFPException */ function compute($vars) { $parameters = $this->mParameters; $result = null; if (!wfRunHooks('AbuseFilter-interceptVariable', array($this->mMethod, $vars, $parameters, &$result))) { return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); } switch ($this->mMethod) { case 'diff': $text1Var = $parameters['oldtext-var']; $text2Var = $parameters['newtext-var']; $text1 = $vars->getVar($text1Var)->toString() . "\n"; $text2 = $vars->getVar($text2Var)->toString() . "\n"; $result = wfDiff($text1, $text2); break; case 'diff-split': $diff = $vars->getVar($parameters['diff-var'])->toString(); $line_prefix = $parameters['line-prefix']; $diff_lines = explode("\n", $diff); $interest_lines = array(); foreach ($diff_lines as $line) { if (substr($line, 0, 1) === $line_prefix) { $interest_lines[] = substr($line, strlen($line_prefix)); } } $result = $interest_lines; break; case 'links-from-wikitext': // This should ONLY be used when sharing a parse operation with the edit. /* @var WikiPage $article */ $article = $parameters['article']; if ($article !== null && (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT)) { $textVar = $parameters['text-var']; // XXX: Use prepareContentForEdit. But we need a Content object for that. $new_text = $vars->getVar($textVar)->toString(); $content = ContentHandler::makeContent($new_text, $article->getTitle()); $editInfo = $article->prepareContentForEdit($content); $links = array_keys($editInfo->output->getExternalLinks()); $result = $links; break; } // Otherwise fall back to database // Otherwise fall back to database case 'links-from-wikitext-nonedit': case 'links-from-wikitext-or-database': // TODO: use Content object instead, if available! In any case, use WikiPage, not Article. $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); if ($vars->getVar('context')->toString() == 'filter') { $links = $this->getLinksFromDB($article); wfDebug("AbuseFilter: loading old links from DB\n"); } elseif (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT) { wfDebug("AbuseFilter: loading old links from Parser\n"); $textVar = $parameters['text-var']; $wikitext = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($wikitext, $article); $links = array_keys($editInfo->output->getExternalLinks()); } else { // TODO: Get links from Content object. But we don't have the content object. // And for non-text content, $wikitext is usually not going to be a valid // serialization, but rather some dummy text for filtering. $links = array(); } $result = $links; break; case 'link-diff-added': case 'link-diff-removed': $oldLinkVar = $parameters['oldlink-var']; $newLinkVar = $parameters['newlink-var']; $oldLinks = $vars->getVar($oldLinkVar)->toString(); $newLinks = $vars->getVar($newLinkVar)->toString(); $oldLinks = explode("\n", $oldLinks); $newLinks = explode("\n", $newLinks); if ($this->mMethod == 'link-diff-added') { $result = array_diff($newLinks, $oldLinks); } if ($this->mMethod == 'link-diff-removed') { $result = array_diff($oldLinks, $newLinks); } break; case 'parse-wikitext': // Should ONLY be used when sharing a parse operation with the edit. $article = $parameters['article']; if ($article !== null && (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT)) { $textVar = $parameters['wikitext-var']; // XXX: Use prepareContentForEdit. But we need a Content object for that. $new_text = $vars->getVar($textVar)->toString(); $editInfo = $article->prepareTextForEdit($new_text); if (isset($parameters['pst']) && $parameters['pst']) { $result = $editInfo->pstContent->serialize($editInfo->format); } else { $newHTML = $editInfo->output->getText(); // Kill the PP limit comments. Ideally we'd just remove these by not setting the // parser option, but then we can't share a parse operation with the edit, which is bad. $result = preg_replace('/<!--\\s*NewPP limit report[^>]*-->\\s*$/si', '', $newHTML); } break; } // Otherwise fall back to database // Otherwise fall back to database case 'parse-wikitext-nonedit': // TODO: use Content object instead, if available! In any case, use WikiPage, not Article. $article = self::articleFromTitle($parameters['namespace'], $parameters['title']); $textVar = $parameters['wikitext-var']; if (!defined('MW_SUPPORTS_CONTENTHANDLER') || $article->getContentModel() === CONTENT_MODEL_WIKITEXT) { if (isset($parameters['pst']) && $parameters['pst']) { // $textVar is already PSTed when it's not loaded from an ongoing edit. $result = $vars->getVar($textVar)->toString(); } else { $text = $vars->getVar($textVar)->toString(); $editInfo = $this->parseNonEditWikitext($text, $article); $result = $editInfo->output->getText(); } } else { // TODO: Parser Output from Content object. But we don't have the content object. // And for non-text content, $wikitext is usually not going to be a valid // serialization, but rather some dummy text for filtering. $result = ''; } break; case 'strip-html': $htmlVar = $parameters['html-var']; $html = $vars->getVar($htmlVar)->toString(); $result = StringUtils::delimiterReplace('<', '>', '', $html); break; case 'load-recent-authors': $cutOff = $parameters['cutoff']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); if (!$title->exists()) { $result = ''; break; } $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('revision', 'DISTINCT rev_user_text', array('rev_page' => $title->getArticleID(), 'rev_timestamp<' . $dbr->addQuotes($dbr->timestamp($cutOff))), __METHOD__, array('ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 10)); $users = array(); foreach ($res as $row) { $users[] = $row->rev_user_text; } $result = $users; break; case 'get-page-restrictions': $action = $parameters['action']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $rights = $title->getRestrictions($action); $rights = count($rights) ? $rights : array(); $result = $rights; break; case 'simple-user-accessor': $user = $parameters['user']; $method = $parameters['method']; if (!$user) { throw new MWException('No user parameter given.'); } $obj = self::getUserObject($user); if (!$obj) { throw new MWException("Invalid username {$user}"); } $result = call_user_func(array($obj, $method)); break; case 'user-age': $user = $parameters['user']; $asOf = $parameters['asof']; $obj = self::getUserObject($user); if ($obj->getId() == 0) { $result = 0; break; } $registration = $obj->getRegistration(); $result = wfTimestamp(TS_UNIX, $asOf) - wfTimestampOrNull(TS_UNIX, $registration); break; case 'user-groups': // Deprecated but needed by old log entries $user = $parameters['user']; $obj = self::getUserObject($user); $result = $obj->getEffectiveGroups(); break; case 'length': $s = $vars->getVar($parameters['length-var'])->toString(); $result = strlen($s); break; case 'subtract': $v1 = $vars->getVar($parameters['val1-var'])->toFloat(); $v2 = $vars->getVar($parameters['val2-var'])->toFloat(); $result = $v1 - $v2; break; case 'revision-text-by-id': $rev = Revision::newFromId($parameters['revid']); $result = AbuseFilter::revisionToString($rev); break; case 'revision-text-by-timestamp': $timestamp = $parameters['timestamp']; $title = Title::makeTitle($parameters['namespace'], $parameters['title']); $dbr = wfGetDB(DB_SLAVE); $rev = Revision::loadFromTimestamp($dbr, $title, $timestamp); $result = AbuseFilter::revisionToString($rev); break; default: if (wfRunHooks('AbuseFilter-computeVariable', array($this->mMethod, $vars, $parameters, &$result))) { throw new AFPException('Unknown variable compute type ' . $this->mMethod); } } return $result instanceof AFPData ? $result : AFPData::newFromPHPVar($result); }
function stringifyActions($actions) { $lines = array(); ksort($actions); foreach ($actions as $action => $parameters) { $lines[] = AbuseFilter::formatAction($action, $parameters); } if (!count($lines)) { $lines[] = ''; } return $lines; }
function loadHistoryItem($id) { $dbr = wfGetDB(DB_SLAVE); // Load the row. $row = $dbr->selectRow('abuse_filter_history', '*', array('afh_id' => $id), __METHOD__); return AbuseFilter::translateFromHistory($row); }
public function execute($subpage) { $out = $this->getOutput(); $request = $this->getRequest(); $out->addModuleStyles('ext.abuseFilter'); $view = 'AbuseFilterViewList'; $this->setHeaders(); $this->loadParameters($subpage); $out->setPageTitle($this->msg('abusefilter-management')); // Are we allowed? $this->checkPermissions(); if ($request->getVal('result') == 'success') { $out->setSubtitle(wfMsg('abusefilter-edit-done-subtitle')); $changedFilter = intval($request->getVal('changedfilter')); $out->wrapWikiMsg('<p class="success">$1</p>', array('abusefilter-edit-done', $changedFilter)); } $this->mHistoryID = null; $pageType = 'home'; $params = explode('/', $subpage); // Filter by removing blanks. foreach ($params as $index => $param) { if ($param === '') { unset($params[$index]); } } $params = array_values($params); if ($subpage == 'tools') { $view = 'AbuseFilterViewTools'; $pageType = 'tools'; } if (count($params) == 2 && $params[0] == 'revert' && is_numeric($params[1])) { $this->mFilter = $params[1]; $view = 'AbuseFilterViewRevert'; $pageType = 'revert'; } if (count($params) && $params[0] == 'test') { $view = 'AbuseFilterViewTestBatch'; $pageType = 'test'; } if (count($params) && $params[0] == 'examine') { $view = 'AbuseFilterViewExamine'; $pageType = 'examine'; } if (!empty($params[0]) && ($params[0] == 'history' || $params[0] == 'log')) { $pageType = ''; if (count($params) == 1) { $view = 'AbuseFilterViewHistory'; $pageType = 'recentchanges'; } elseif (count($params) == 2) { # Second param is a filter ID $view = 'AbuseFilterViewHistory'; $this->mFilter = $params[1]; } elseif (count($params) == 4 && $params[2] == 'item') { $this->mFilter = $params[1]; $this->mHistoryID = $params[3]; $view = 'AbuseFilterViewEdit'; } elseif (count($params) == 5 && $params[2] == 'diff') { // Special:AbuseFilter/history/<filter>/diff/<oldid>/<newid> $view = 'AbuseFilterViewDiff'; } } if (is_numeric($subpage) || $subpage == 'new') { $this->mFilter = $subpage; $view = 'AbuseFilterViewEdit'; $pageType = 'edit'; } if ($subpage == 'import') { $view = 'AbuseFilterViewImport'; $pageType = 'import'; } // Links at the top AbuseFilter::addNavigationLinks($this->getContext(), $pageType); $v = new $view($this, $params); $v->show(); }
function formatRow($row, $li = true) { global $wgLang, $wgUser; # One-time setup static $sk = null; $actionLinks = array(); if (is_null($sk)) { $sk = $wgUser->getSkin(); } $title = Title::makeTitle($row->afl_namespace, $row->afl_title); if (!$row->afl_wiki) { $pageLink = $sk->link($title); } else { $pageLink = WikiMap::makeForeignLink($row->afl_wiki, $row->afl_title); } if (!$row->afl_wiki) { // Local user $user = $sk->userLink($row->afl_user, $row->afl_user_text) . $sk->userToolLinks($row->afl_user, $row->afl_user_text); } else { $user = WikiMap::foreignUserLink($row->afl_wiki, $row->afl_user_text); $user .= ' (' . WikiMap::getWikiName($row->afl_wiki) . ')'; } $timestamp = $wgLang->timeanddate($row->afl_timestamp, true); $actions_taken = $row->afl_actions; if (!strlen(trim($actions_taken))) { $actions_taken = wfMsg('abusefilter-log-noactions'); } else { $actions = explode(',', $actions_taken); $displayActions = array(); foreach ($actions as $action) { $displayActions[] = AbuseFilter::getActionDisplay($action); } $actions_taken = $wgLang->commaList($displayActions); } $globalIndex = AbuseFilter::decodeGlobalName($row->afl_filter); global $wgOut; if ($globalIndex) { // Pull global filter description $parsed_comments = $wgOut->parseInline(AbuseFilter::getGlobalFilterDescription($globalIndex)); } else { $parsed_comments = $wgOut->parseInline($row->af_public_comments); } if (self::canSeeDetails()) { $examineTitle = SpecialPage::getTitleFor('AbuseFilter', 'examine/log/' . $row->afl_id); $detailsLink = $sk->makeKnownLinkObj($this->getTitle($row->afl_id), wfMsg('abusefilter-log-detailslink')); $examineLink = $sk->link($examineTitle, wfMsgExt('abusefilter-changeslist-examine', 'parseinline'), array()); $actionLinks[] = $detailsLink; $actionLinks[] = $examineLink; if ($wgUser->isAllowed('abusefilter-hide-log')) { $hideLink = $sk->link($this->getTitle(), wfMsg('abusefilter-log-hidelink'), array(), array('hide' => $row->afl_id)); $actionLinks[] = $hideLink; } if ($globalIndex) { global $wgAbuseFilterCentralDB; $globalURL = WikiMap::getForeignURL($wgAbuseFilterCentralDB, 'Special:AbuseFilter/' . $globalIndex); $linkText = wfMsgExt('abusefilter-log-detailedentry-global', 'parseinline', array($globalIndex)); $filterLink = $sk->makeExternalLink($globalURL, $linkText); } else { $title = SpecialPage::getTitleFor('AbuseFilter', $row->afl_filter); $linkText = wfMsgExt('abusefilter-log-detailedentry-local', 'parseinline', array($row->afl_filter)); $filterLink = $sk->link($title, $linkText); } $description = wfMsgExt('abusefilter-log-detailedentry-meta', array('parseinline', 'replaceafter'), array($timestamp, $user, $filterLink, $row->afl_action, $pageLink, $actions_taken, $parsed_comments, $wgLang->pipeList($actionLinks))); } else { $description = wfMsgExt('abusefilter-log-entry', array('parseinline', 'replaceafter'), array($timestamp, $user, $row->afl_action, $sk->link($title), $actions_taken, $parsed_comments)); } if ($row->afl_deleted) { $description .= ' ' . wfMsgExt('abusefilter-log-hidden', 'parseinline'); } return $li ? Xml::tags('li', null, $description) : $description; }
public function execute() { $params = $this->extractRequestParams(); $result = AbuseFilter::evaluateExpression($params['expression']); $this->getResult()->addValue(null, $this->getModuleName(), array('result' => $result)); }
static function formatAction($action, $parameters) { global $wgLang; if (count($parameters) == 0) { $displayAction = AbuseFilter::getActionDisplay($action); } else { $displayAction = AbuseFilter::getActionDisplay($action) . wfMsgExt('colon-separator', 'escapenoentities') . $wgLang->semicolonList($parameters); } return $displayAction; }
public static function onUploadVerification($saveName, $tempName, &$error) { $vars = new AbuseFilterVariableHolder(); global $wgUser; $title = Title::makeTitle(NS_FILE, $saveName); $vars->addHolder(AbuseFilterVariableHolder::merge(AbuseFilter::generateUserVars($wgUser), AbuseFilter::generateTitleVars($title, 'FILE'))); $vars->setVar('ACTION', 'upload'); $vars->setVar('file_sha1', sha1_file($tempName)); // TODO share with save $filter_result = AbuseFilter::filterAction($vars, $title); if (is_string($filter_result)) { $error = $filter_result; } return $filter_result == '' || $filter_result === true; }
function formatValue($name, $value) { $lang = $this->getLanguage(); $row = $this->mCurrentRow; switch ($name) { case 'afh_filter': $formatted = $lang->formatNum($row->afh_filter); break; case 'afh_timestamp': $title = SpecialPage::getTitleFor('AbuseFilter', 'history/' . $row->afh_filter . '/item/' . $row->afh_id); $formatted = Linker::link($title, $lang->timeanddate($row->afh_timestamp, true)); break; case 'afh_user_text': $formatted = Linker::userLink($row->afh_user, $row->afh_user_text) . ' ' . Linker::userToolLinks($row->afh_user, $row->afh_user_text); break; case 'afh_public_comments': $formatted = htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false); break; case 'afh_flags': $formatted = AbuseFilter::formatFlags($value); break; case 'afh_actions': $actions = unserialize($value); $display_actions = ''; foreach ($actions as $action => $parameters) { $displayAction = AbuseFilter::formatAction($action, $parameters); $display_actions .= Xml::tags('li', null, $displayAction); } $display_actions = Xml::tags('ul', null, $display_actions); $formatted = $display_actions; break; case 'afh_id': $formatted = ''; if (AbuseFilter::getFirstFilterChange($row->afh_filter) != $value) { // Set a link to a diff with the previous version if this isn't the first edit to the filter $title = $this->mPage->getTitle('history/' . $row->afh_filter . "/diff/prev/{$value}"); $formatted = Linker::link($title, $this->msg('abusefilter-history-diff')->parse()); } break; default: $formatted = "Unable to format {$name}"; break; } $mappings = array_flip(AbuseFilter::$history_mappings) + array('afh_actions' => 'actions', 'afh_id' => 'id'); $changed = explode(',', $row->afh_changed_fields); $fieldChanged = false; if ($name == 'afh_flags') { // This is a bit freaky, but it works. // Basically, returns true if any of those filters are in the $changed array. $filters = array('af_enabled', 'af_hidden', 'af_deleted', 'af_global'); if (count(array_diff($filters, $changed)) < count($filters)) { $fieldChanged = true; } } elseif (in_array($mappings[$name], $changed)) { $fieldChanged = true; } if ($fieldChanged) { $formatted = Xml::tags('div', array('class' => 'mw-abusefilter-history-changed'), $formatted); } return $formatted; }
function revertAction($action, $result) { switch ($action) { case 'block': $block = Block::newFromTarget(User::whoIs($result['userid'])); if (!$block || $block->getBy() != AbuseFilter::getFilterUser()->getId()) { return false; // Not blocked by abuse filter. } $block->delete(); $log = new LogPage('block'); $log->addEntry('unblock', Title::makeTitle(NS_USER, $result['user']), wfMsgForContent('abusefilter-revert-reason', $this->mPage->mFilter, $this->mReason)); break; case 'blockautopromote': global $wgMemc; $wgMemc->delete(AbuseFilter::autopromoteBlockKey(User::newFromId($result['userid']))); break; case 'degroup': // Pull the user's groups from the vars. $oldGroups = $result['vars']['USER_GROUPS']; $oldGroups = explode(',', $oldGroups); $oldGroups = array_diff($oldGroups, array_intersect($oldGroups, User::getImplicitGroups())); $rows = array(); foreach ($oldGroups as $group) { $rows[] = array('ug_user' => $result['userid'], 'ug_group' => $group); } // Cheat a little bit. User::addGroup repeatedly is too slow. $user = User::newFromId($result['userid']); $currentGroups = $user->getGroups(); $newGroups = array_merge($oldGroups, $currentGroups); // Don't do anything if there are no groups to add. if (!count(array_diff($newGroups, $currentGroups))) { return; } $dbw = wfGetDB(DB_MASTER); $dbw->insert('user_groups', $rows, __METHOD__, array('IGNORE')); $user->invalidateCache(); $log = new LogPage('rights'); $log->addEntry('rights', $user->getUserPage(), wfMsgForContent('abusefilter-revert-reason', $this->mPage->mFilter, $this->mReason), array(implode(',', $currentGroups), implode(',', $newGroups))); } }
function showExaminer($vars) { $output = $this->getOutput(); if (!$vars) { $output->addWikiMsg('abusefilter-examine-incompatible'); return; } if ($vars instanceof AbuseFilterVariableHolder) { $vars = $vars->exportAllVars(); } $html = ''; $output->addModules('ext.abuseFilter.examine'); // Add test bit if ($this->getUser()->isAllowed('abusefilter-modify')) { $tester = Xml::tags('h2', null, $this->msg('abusefilter-examine-test')->parse()); $tester .= AbuseFilter::buildEditBox($this->mTestFilter, 'wpTestFilter', false); $tester .= "\n" . Xml::inputLabel($this->msg('abusefilter-test-load-filter')->text(), 'wpInsertFilter', 'mw-abusefilter-load-filter', 10, '') . ' ' . Xml::element('input', array('type' => 'button', 'value' => $this->msg('abusefilter-test-load')->text(), 'id' => 'mw-abusefilter-load')); $html .= Xml::tags('div', array('id' => 'mw-abusefilter-examine-editor'), $tester); $html .= Xml::tags('p', null, Xml::element('input', array('type' => 'button', 'value' => $this->msg('abusefilter-examine-test-button')->text(), 'id' => 'mw-abusefilter-examine-test')) . Xml::element('div', array('id' => 'mw-abusefilter-syntaxresult', 'style' => 'display: none;'), ' ')); } // Variable dump $html .= Xml::tags('h2', null, $this->msg('abusefilter-examine-vars', 'parseinline')->parse()); $html .= AbuseFilter::buildVarDumpTable($vars); $output->addHTML($html); }
/** * Check for abusive or spammy content * * Check the following in sequence (cheapest processing to most expensive, * returning if we get a hit): * 1) Respect $wgSpamRegex * 2) Check SpamBlacklist * 3) Check AbuseFilter * * @param $value string the text to check * @param $pageId int the page ID */ private function findAbuse(&$value, $pageId) { // Respect $wgSpamRegex global $wgSpamRegex; if (is_array($wgSpamRegex) && count($wgSpamRegex) > 0 || is_string($wgSpamRegex) && strlen($wgSpamRegex) > 0) { // In older versions, $wgSpamRegex may be a single string rather than // an array of regexes, so make it compatible. $regexes = (array) $wgSpamRegex; foreach ($regexes as $regex) { if (preg_match($regex, $value)) { return true; } } } // Create a fake title so we can pretend this is an article edit $title = Title::newFromText('__article_feedback_5__'); // Check SpamBlacklist, if installed if (function_exists('wfSpamBlacklistObject')) { $spam = wfSpamBlacklistObject(); $ret = $spam->filter($title, $value, ''); if ($ret !== false) { return true; } } // Check AbuseFilter, if installed if (class_exists('AbuseFilter')) { global $wgUser; $vars = new AbuseFilterVariableHolder(); $vars->addHolder(AbuseFilter::generateUserVars($wgUser)); $vars->addHolder(AbuseFilter::generateTitleVars($title, 'FEEDBACK')); $vars->setVar('SUMMARY', 'Article Feedback 5'); $vars->setVar('ACTION', 'feedback'); $vars->setVar('old_wikitext', ''); $vars->setVar('new_wikitext', $value); $vars->addHolder(AbuseFilter::getEditVars($title)); $filter_result = AbuseFilter::filterAction($vars, $title); return $filter_result != '' && $filter_result !== true; } return false; }
public function execute() { $user = $this->getUser(); $errors = $this->getTitle()->getUserPermissionsErrors('abusefilter-log', $user); if (count($errors)) { $this->dieUsageMsg($errors[0]); return; } $params = $this->extractRequestParams(); $prop = array_flip($params['prop']); $fld_ids = isset($prop['ids']); $fld_filter = isset($prop['filter']); $fld_user = isset($prop['user']); $fld_ip = isset($prop['ip']); $fld_title = isset($prop['title']); $fld_action = isset($prop['action']); $fld_details = isset($prop['details']); $fld_result = isset($prop['result']); $fld_timestamp = isset($prop['timestamp']); $fld_hidden = isset($prop['hidden']); $fld_revid = isset($prop['revid']); if ($fld_ip && !$user->isAllowed('abusefilter-private')) { $this->dieUsage('You don\'t have permission to view IP addresses', 'permissiondenied'); } if ($fld_details && !$user->isAllowed('abusefilter-log-detail')) { $this->dieUsage('You don\'t have permission to view detailed abuse log entries', 'permissiondenied'); } // Match permissions for viewing events on private filters to SpecialAbuseLog (bug 42814) if ($params['filter'] && !(AbuseFilterView::canViewPrivate() || $user->isAllowed('abusefilter-log-private'))) { // A specific filter parameter is set but the user isn't allowed to view all filters if (!is_array($params['filter'])) { $params['filter'] = array($params['filter']); } foreach ($params['filter'] as $filter) { if (AbuseFilter::filterHidden($filter)) { $this->dieUsage('You don\'t have permission to view log entries for private filters', 'permissiondenied'); } } } $result = $this->getResult(); $this->addTables('abuse_filter_log'); $this->addFields('afl_timestamp'); $this->addFields('afl_rev_id'); $this->addFields('afl_deleted'); $this->addFields('afl_filter'); $this->addFieldsIf('afl_id', $fld_ids); $this->addFieldsIf('afl_user_text', $fld_user); $this->addFieldsIf('afl_ip', $fld_ip); $this->addFieldsIf(array('afl_namespace', 'afl_title'), $fld_title); $this->addFieldsIf('afl_action', $fld_action); $this->addFieldsIf('afl_var_dump', $fld_details); $this->addFieldsIf('afl_actions', $fld_result); if ($fld_filter) { $this->addTables('abuse_filter'); $this->addFields('af_public_comments'); $this->addJoinConds(array('abuse_filter' => array('LEFT JOIN', 'af_id=afl_filter'))); } $this->addOption('LIMIT', $params['limit'] + 1); $this->addWhereRange('afl_timestamp', $params['dir'], $params['start'], $params['end']); $db = $this->getDB(); $notDeletedCond = SpecialAbuseLog::getNotDeletedCond($db); if (isset($params['user'])) { $u = User::newFromName($params['user']); if ($u) { // Username normalisation $params['user'] = $u->getName(); $userId = $u->getId(); } elseif (IP::isIPAddress($params['user'])) { // It's an IP, sanitize it $params['user'] = IP::sanitizeIP($params['user']); $userId = 0; } if (isset($userId)) { // Only add the WHERE for user in case it's either a valid user (but not necessary an existing one) or an IP $this->addWhere(array('afl_user' => $userId, 'afl_user_text' => $params['user'])); } } $this->addWhereIf(array('afl_filter' => $params['filter']), isset($params['filter'])); $this->addWhereIf($notDeletedCond, !SpecialAbuseLog::canSeeHidden($user)); $title = $params['title']; if (!is_null($title)) { $titleObj = Title::newFromText($title); if (is_null($titleObj)) { $this->dieUsageMsg(array('invalidtitle', $title)); } $this->addWhereFld('afl_namespace', $titleObj->getNamespace()); $this->addWhereFld('afl_title', $titleObj->getDBkey()); } $res = $this->select(__METHOD__); $count = 0; foreach ($res as $row) { if (++$count > $params['limit']) { // We've had enough $ts = new MWTimestamp($row->afl_timestamp); $this->setContinueEnumParameter('start', $ts->getTimestamp(TS_ISO_8601)); break; } if (SpecialAbuseLog::isHidden($row) && !SpecialAbuseLog::canSeeHidden($user)) { continue; } $canSeeDetails = SpecialAbuseLog::canSeeDetails($row->afl_filter); $entry = array(); if ($fld_ids) { $entry['id'] = intval($row->afl_id); $entry['filter_id'] = ''; if ($canSeeDetails) { $entry['filter_id'] = $row->afl_filter; } } if ($fld_filter) { $entry['filter'] = $row->af_public_comments; } if ($fld_user) { $entry['user'] = $row->afl_user_text; } if ($fld_ip) { $entry['ip'] = $row->afl_ip; } if ($fld_title) { $title = Title::makeTitle($row->afl_namespace, $row->afl_title); ApiQueryBase::addTitleInfo($entry, $title); } if ($fld_action) { $entry['action'] = $row->afl_action; } if ($fld_result) { $entry['result'] = $row->afl_actions; } if ($fld_revid && !is_null($row->afl_rev_id)) { $entry['revid'] = ''; if ($canSeeDetails) { $entry['revid'] = $row->afl_rev_id; } } if ($fld_timestamp) { $ts = new MWTimestamp($row->afl_timestamp); $entry['timestamp'] = $ts->getTimestamp(TS_ISO_8601); } if ($fld_details) { $entry['details'] = array(); if ($canSeeDetails) { $vars = AbuseFilter::loadVarDump($row->afl_var_dump); if ($vars instanceof AbuseFilterVariableHolder) { $entry['details'] = $vars->exportAllVars(); } else { $entry['details'] = array_change_key_case($vars, CASE_LOWER); } } } if ($fld_hidden) { $val = SpecialAbuseLog::isHidden($row); if ($val) { $entry['hidden'] = $val; } } if ($entry) { $fit = $result->addValue(array('query', $this->getModuleName()), null, $entry); if (!$fit) { $ts = new MWTimestamp($row->afl_timestamp); $this->setContinueEnumParameter('start', $ts->getTimestamp(TS_ISO_8601)); break; } } } $result->setIndexedTagName_internal(array('query', $this->getModuleName()), 'item'); }
/** * @param $row * @param $isListItem bool * @return String */ function formatRow($row, $isListItem = true) { $user = $this->getUser(); $lang = $this->getLanguage(); $actionLinks = array(); $title = Title::makeTitle($row->afl_namespace, $row->afl_title); $diffLink = false; if (self::isHidden($row) && !$this->canSeeHidden()) { return ''; } if (!$row->afl_wiki) { $pageLink = Linker::link($title); if ($row->afl_rev_id) { $diffLink = Linker::link($title, wfMessage('abusefilter-log-diff')->parse(), array(), array('diff' => 'prev', 'oldid' => $row->afl_rev_id)); } } else { $pageLink = WikiMap::makeForeignLink($row->afl_wiki, $row->afl_title); if ($row->afl_rev_id) { $diffUrl = WikiMap::getForeignURL($row->afl_wiki, $row->afl_title); $diffUrl = wfAppendQuery($diffUrl, array('diff' => 'prev', 'oldid' => $row->afl_rev_id)); $diffLink = Linker::makeExternalLink($diffUrl, wfMessage('abusefilter-log-diff')->parse()); } } if (!$row->afl_wiki) { // Local user $userLink = Linker::userLink($row->afl_user, $row->afl_user_text) . Linker::userToolLinks($row->afl_user, $row->afl_user_text, true); } else { $userLink = WikiMap::foreignUserLink($row->afl_wiki, $row->afl_user_text); $userLink .= ' (' . WikiMap::getWikiName($row->afl_wiki) . ')'; } $timestamp = $lang->timeanddate($row->afl_timestamp, true); $actions_taken = $row->afl_actions; if (!strlen(trim($actions_taken))) { $actions_taken = $this->msg('abusefilter-log-noactions')->text(); } else { $actions = explode(',', $actions_taken); $displayActions = array(); foreach ($actions as $action) { $displayActions[] = AbuseFilter::getActionDisplay($action); } $actions_taken = $lang->commaList($displayActions); } $globalIndex = AbuseFilter::decodeGlobalName($row->afl_filter); if ($globalIndex) { // Pull global filter description $parsed_comments = $this->getOutput()->parseInline(AbuseFilter::getGlobalFilterDescription($globalIndex)); $filter_hidden = null; } else { $parsed_comments = $this->getOutput()->parseInline($row->af_public_comments); $filter_hidden = $row->af_hidden; } if (self::canSeeDetails($row->afl_filter, $filter_hidden)) { if ($isListItem) { $detailsLink = Linker::linkKnown($this->getPageTitle($row->afl_id), $this->msg('abusefilter-log-detailslink')->escaped()); $actionLinks[] = $detailsLink; } $examineTitle = SpecialPage::getTitleFor('AbuseFilter', 'examine/log/' . $row->afl_id); $examineLink = Linker::link($examineTitle, $this->msg('abusefilter-changeslist-examine')->parse(), array()); $actionLinks[] = $examineLink; if ($diffLink) { $actionLinks[] = $diffLink; } if ($user->isAllowed('abusefilter-hide-log')) { $hideLink = Linker::link($this->getPageTitle(), $this->msg('abusefilter-log-hidelink')->text(), array(), array('hide' => $row->afl_id)); $actionLinks[] = $hideLink; } if ($globalIndex) { global $wgAbuseFilterCentralDB; $globalURL = WikiMap::getForeignURL($wgAbuseFilterCentralDB, 'Special:AbuseFilter/' . $globalIndex); $linkText = wfMessage('abusefilter-log-detailedentry-global')->numParams($globalIndex)->escaped(); $filterLink = Linker::makeExternalLink($globalURL, $linkText); } else { $title = SpecialPage::getTitleFor('AbuseFilter', $row->afl_filter); $linkText = wfMessage('abusefilter-log-detailedentry-local')->numParams($row->afl_filter)->escaped(); $filterLink = Linker::link($title, $linkText); } $description = $this->msg('abusefilter-log-detailedentry-meta')->rawParams($timestamp, $userLink, $filterLink, $row->afl_action, $pageLink, $actions_taken, $parsed_comments, $lang->pipeList($actionLinks), $row->afl_user_text)->parse(); } else { if ($diffLink) { $msg = 'abusefilter-log-entry-withdiff'; } else { $msg = 'abusefilter-log-entry'; } $description = $this->msg($msg)->rawParams($timestamp, $userLink, $row->afl_action, $pageLink, $actions_taken, $parsed_comments, $diffLink)->parse(); } if (self::isHidden($row) === true) { $description .= ' ' . $this->msg('abusefilter-log-hidden')->parse(); $class = 'afl-hidden'; } elseif (self::isHidden($row) === 'implicit') { $description .= ' ' . $this->msg('abusefilter-log-hidden-implicit')->parse(); } if ($isListItem) { return Xml::tags('li', isset($class) ? array('class' => $class) : null, $description); } else { return Xml::tags('span', isset($class) ? array('class' => $class) : null, $description); } }
public function execute($subpage) { global $wgUser, $wgOut, $wgRequest, $wgAbuseFilterStyleVersion, $wgScriptPath; $wgOut->addScript('<style type="text/css" media="all">/*<![CDATA[*/ @import "/extensions/AbuseFilter/abusefilter.css"/*]]>*/</style>'); $view = 'AbuseFilterViewList'; $this->setHeaders(); $this->loadParameters($subpage); $wgOut->setPageTitle(wfMsg('abusefilter-management')); // Are we allowed? if (!$wgUser->isAllowed('abusefilter-view')) { $this->displayRestrictionError(); return; } if ($wgRequest->getVal('result') == 'success') { $wgOut->setSubtitle(wfMsg('abusefilter-edit-done-subtitle')); $changedFilter = intval($wgRequest->getVal('changedfilter')); $wgOut->wrapWikiMsg('<p class="success">$1</p>', array('abusefilter-edit-done', $changedFilter)); } $this->mSkin = $wgUser->getSkin(); $this->mHistoryID = null; $pageType = 'home'; $params = explode('/', $subpage); // Filter by removing blanks. foreach ($params as $index => $param) { if ($param === '') { unset($params[$index]); } } $params = array_values($params); if ($subpage == 'tools') { $view = 'AbuseFilterViewTools'; $pageType = 'tools'; } if (count($params) == 2 && $params[0] == 'revert' && is_numeric($params[1])) { $this->mFilter = $params[1]; $view = 'AbuseFilterViewRevert'; $pageType = 'revert'; } if (count($params) && $params[0] == 'test') { $view = 'AbuseFilterViewTestBatch'; $pageType = 'test'; } if (count($params) && $params[0] == 'examine') { $view = 'AbuseFilterViewExamine'; $pageType = 'examine'; } if (!empty($params[0]) && ($params[0] == 'history' || $params[0] == 'log')) { $pageType = ''; if (count($params) == 1) { $view = 'AbuseFilterViewHistory'; $pageType = 'recentchanges'; } elseif (count($params) == 2) { # # Second param is a filter ID $view = 'AbuseFilterViewHistory'; $this->mFilter = $params[1]; } elseif (count($params) == 4 && $params[2] == 'item') { $this->mFilter = $params[1]; $this->mHistoryID = $params[3]; $view = 'AbuseFilterViewEdit'; } elseif (count($params) == 5 && $params[2] == 'diff') { // Special:AbuseFilter/history/<filter>/diff/<oldid>/<newid> $view = 'AbuseFilterViewDiff'; } } if (is_numeric($subpage) || $subpage == 'new') { $this->mFilter = $subpage; $view = 'AbuseFilterViewEdit'; $pageType = 'edit'; } if ($subpage == 'import') { $view = 'AbuseFilterViewImport'; $pageType = 'import'; } // Links at the top AbuseFilter::addNavigationLinks($wgOut, $this->mSkin, $pageType); $v = new $view($this, $params); $v->show(); }
function showExaminer($vars) { global $wgOut, $wgUser; if (!$vars) { $wgOut->addWikiMsg('abusefilter-examine-incompatible'); return; } if ($vars instanceof AbuseFilterVariableHolder) { $vars = $vars->exportAllVars(); } $output = ''; // Send armoured as JSON -- I totally give up on trying to send it as a proper object. $wgOut->addInlineScript("var wgExamineVars = " . Xml::encodeJsVar(json_encode($vars)) . ";"); $wgOut->addInlineScript(file_get_contents(dirname(__FILE__) . '/examine.js')); // Add messages $msg = array(); $msg['match'] = wfMsg('abusefilter-examine-match'); $msg['nomatch'] = wfMsg('abusefilter-examine-nomatch'); $msg['syntaxerror'] = wfMsg('abusefilter-examine-syntaxerror'); $wgOut->addInlineScript("var wgMessageMatch = " . Xml::encodeJsVar($msg['match']) . ";\n" . "var wgMessageNomatch = " . Xml::encodeJsVar($msg['nomatch']) . ";\n" . "var wgMessageError = " . Xml::encodeJsVar($msg['syntaxerror']) . ";\n"); // Add test bit if ($wgUser->isAllowed('abusefilter-modify')) { $tester = Xml::tags('h2', null, wfMsgExt('abusefilter-examine-test', 'parseinline')); $tester .= AbuseFilter::buildEditBox($this->mTestFilter, 'wpTestFilter', false); $tester .= "\n" . Xml::inputLabel(wfMsg('abusefilter-test-load-filter'), 'wpInsertFilter', 'mw-abusefilter-load-filter', 10, '') . ' ' . Xml::element('input', array('type' => 'button', 'value' => wfMsg('abusefilter-test-load'), 'id' => 'mw-abusefilter-load')); $output .= Xml::tags('div', array('id' => 'mw-abusefilter-examine-editor'), $tester); $output .= Xml::tags('p', null, Xml::element('input', array('type' => 'button', 'value' => wfMsg('abusefilter-examine-test-button'), 'id' => 'mw-abusefilter-examine-test')) . Xml::element('div', array('id' => 'mw-abusefilter-syntaxresult', 'style' => 'display: none;'), ' ')); } // Variable dump $output .= Xml::tags('h2', null, wfMsgExt('abusefilter-examine-vars', 'parseinline')); $output .= AbuseFilter::buildVarDumpTable($vars); $wgOut->addHTML($output); }