2012-01-17 06:13:46 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hooks for the spam blacklist extension
|
|
|
|
*/
|
|
|
|
class SpamBlacklistHooks {
|
|
|
|
/**
|
2013-07-25 14:05:13 +00:00
|
|
|
* Hook function for EditFilterMergedContent
|
|
|
|
*
|
|
|
|
* @param IContextSource $context
|
2017-09-01 04:57:27 +00:00
|
|
|
* @param Content $content
|
|
|
|
* @param Status $status
|
|
|
|
* @param string $summary
|
|
|
|
* @param User $user
|
|
|
|
* @param bool $minoredit
|
2012-01-17 06:13:46 +00:00
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
2018-11-02 11:54:59 +00:00
|
|
|
public static function filterMergedContent(
|
2017-06-02 16:02:09 +00:00
|
|
|
IContextSource $context,
|
|
|
|
Content $content,
|
|
|
|
Status $status,
|
|
|
|
$summary,
|
|
|
|
User $user,
|
|
|
|
$minoredit
|
|
|
|
) {
|
2013-07-25 14:05:13 +00:00
|
|
|
$title = $context->getTitle();
|
|
|
|
|
|
|
|
// get the link from the not-yet-saved page content.
|
2014-01-07 22:00:30 +00:00
|
|
|
$editInfo = $context->getWikiPage()->prepareContentForEdit( $content );
|
|
|
|
$pout = $editInfo->output;
|
2013-07-25 14:05:13 +00:00
|
|
|
$links = array_keys( $pout->getExternalLinks() );
|
|
|
|
|
2015-11-28 04:02:57 +00:00
|
|
|
// HACK: treat the edit summary as a link if it contains anything
|
|
|
|
// that looks like it could be a URL or e-mail address.
|
|
|
|
if ( preg_match( '/\S(\.[^\s\d]{2,}|[\/@]\S)/', $summary ) ) {
|
2013-07-25 14:05:13 +00:00
|
|
|
$links[] = $summary;
|
|
|
|
}
|
|
|
|
|
2018-02-25 01:25:04 +00:00
|
|
|
$spamObj = BaseBlacklist::getSpamBlacklist();
|
2013-07-25 14:05:13 +00:00
|
|
|
$matches = $spamObj->filter( $links, $title );
|
|
|
|
|
|
|
|
if ( $matches !== false ) {
|
Actually return errors for action=edit API
Setting 'apiHookResult' results in a "successful" response; if we want
to report an error, we need to use ApiMessage. We already were doing
this for action=upload. Now our action=edit API responses will be
consistent with MediaWiki and other extensions, and will be able to
take advantage of errorformat=html.
Additionally, remove incorrect 'message' value from action=upload
output. It was anyway redundant to the normal error information.
To avoid user interface regressions in VisualEditor, the changes
I3b9c4fef (in VE) and I106dbd3c (in MediaWiki) should be merged first.
Before:
{
"edit": {
"spamblacklist": "example.com/test|example.net/test",
"result": "Failure"
}
}
After:
{
"errors": [
{
"code": "spamblacklist",
"data": {
"spamblacklist": {
"matches": [
"example.com/test",
"example.net/test"
]
}
},
"module": "edit",
"*": "The text you wanted to save was blocked ..."
}
],
"*": "See http://localhost:3080/w/api.php for API usage. ..."
}
For comparison, a 'readonly' error:
{
"errors": [
{
"code": "readonly",
"data": {
"readonlyreason": "foo bar"
},
"module": "main",
"*": "The wiki is currently in read-only mode."
}
],
"*": "See http://localhost:3080/w/api.php for API usage. ..."
}
Bug: T229539
Depends-On: I106dbd3cbdbf7082b1d1f1c1106ece6b19c22a86
Depends-On: I3b9c4fefc0869ef7999c21cef754434febd852ec
Change-Id: Id36aa6bdb8f873fe7deb8123a7fc774103721c01
2019-08-20 18:47:21 +00:00
|
|
|
$error = new ApiMessage(
|
|
|
|
wfMessage( 'spam-blacklisted-link', Message::listParam( $matches ) ),
|
|
|
|
'spamblacklist',
|
|
|
|
[
|
|
|
|
'spamblacklist' => [ 'matches' => $matches ],
|
|
|
|
]
|
|
|
|
);
|
|
|
|
$status->fatal( $error );
|
2012-01-17 06:13:46 +00:00
|
|
|
}
|
2013-07-25 14:05:13 +00:00
|
|
|
|
|
|
|
// Always return true, EditPage will look at $status->isOk().
|
|
|
|
return true;
|
2012-01-17 06:13:46 +00:00
|
|
|
}
|
|
|
|
|
2016-06-30 21:26:36 +00:00
|
|
|
public static function onParserOutputStashForEdit(
|
2017-06-02 16:02:09 +00:00
|
|
|
WikiPage $page,
|
|
|
|
Content $content,
|
|
|
|
ParserOutput $output
|
2016-06-30 21:26:36 +00:00
|
|
|
) {
|
2016-09-09 00:44:26 +00:00
|
|
|
$links = array_keys( $output->getExternalLinks() );
|
2018-02-25 01:25:04 +00:00
|
|
|
$spamObj = BaseBlacklist::getSpamBlacklist();
|
2016-06-30 21:26:36 +00:00
|
|
|
$spamObj->warmCachesForFilter( $page->getTitle(), $links );
|
2016-02-16 21:39:06 +00:00
|
|
|
}
|
|
|
|
|
2012-01-18 23:29:37 +00:00
|
|
|
/**
|
|
|
|
* Verify that the user can send emails
|
|
|
|
*
|
2017-10-07 09:15:06 +00:00
|
|
|
* @param User &$user
|
|
|
|
* @param array &$hookErr
|
2012-01-18 23:29:37 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public static function userCanSendEmail( &$user, &$hookErr ) {
|
2018-02-25 01:25:04 +00:00
|
|
|
$blacklist = BaseBlacklist::getEmailBlacklist();
|
2012-01-18 23:29:37 +00:00
|
|
|
if ( $blacklist->checkUser( $user ) ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-06 16:29:27 +00:00
|
|
|
$hookErr = [ 'spam-blacklisted-email', 'spam-blacklisted-email-text', null ];
|
2012-01-18 23:29:37 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-01-17 06:13:46 +00:00
|
|
|
/**
|
|
|
|
* Hook function for EditFilter
|
|
|
|
* Confirm that a local blacklist page being saved is valid,
|
|
|
|
* and toss back a warning to the user if it isn't.
|
|
|
|
*
|
2017-09-01 20:24:40 +00:00
|
|
|
* @param EditPage $editPage
|
|
|
|
* @param string $text
|
|
|
|
* @param string $section
|
2017-10-07 09:15:06 +00:00
|
|
|
* @param string &$hookError
|
2012-01-17 06:13:46 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2018-11-02 11:54:59 +00:00
|
|
|
public static function validate( EditPage $editPage, $text, $section, &$hookError ) {
|
2017-09-01 20:24:40 +00:00
|
|
|
$title = $editPage->getTitle();
|
|
|
|
$thisPageName = $title->getPrefixedDBkey();
|
2012-01-17 06:13:46 +00:00
|
|
|
|
2017-09-01 20:24:40 +00:00
|
|
|
if ( !BaseBlacklist::isLocalSource( $title ) ) {
|
2017-06-02 16:02:09 +00:00
|
|
|
wfDebugLog( 'SpamBlacklist',
|
|
|
|
"Spam blacklist validator: [[$thisPageName]] not a local blacklist\n"
|
|
|
|
);
|
2012-01-17 06:13:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-01 20:24:40 +00:00
|
|
|
$type = BaseBlacklist::getTypeFromTitle( $title );
|
2012-01-18 23:29:37 +00:00
|
|
|
if ( $type === false ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-17 06:13:46 +00:00
|
|
|
$lines = explode( "\n", $text );
|
|
|
|
|
2012-01-18 23:29:37 +00:00
|
|
|
$badLines = SpamRegexBatch::getBadLines( $lines, BaseBlacklist::getInstance( $type ) );
|
2017-06-06 16:29:27 +00:00
|
|
|
if ( $badLines ) {
|
2017-06-02 16:02:09 +00:00
|
|
|
wfDebugLog( 'SpamBlacklist',
|
|
|
|
"Spam blacklist validator: [[$thisPageName]] given invalid input lines: " .
|
|
|
|
implode( ', ', $badLines ) . "\n"
|
|
|
|
);
|
2012-01-17 06:13:46 +00:00
|
|
|
|
2012-09-02 15:41:39 +00:00
|
|
|
$badList = "*<code>" .
|
|
|
|
implode( "</code>\n*<code>",
|
2012-01-17 06:13:46 +00:00
|
|
|
array_map( 'wfEscapeWikiText', $badLines ) ) .
|
2012-09-02 15:41:39 +00:00
|
|
|
"</code>\n";
|
2012-01-17 06:13:46 +00:00
|
|
|
$hookError =
|
|
|
|
"<div class='errorbox'>" .
|
2012-09-02 15:41:39 +00:00
|
|
|
wfMessage( 'spam-invalid-lines' )->numParams( $badLines )->text() . "<br />" .
|
2012-01-17 06:13:46 +00:00
|
|
|
$badList .
|
|
|
|
"</div>\n" .
|
|
|
|
"<br clear='all' />\n";
|
|
|
|
} else {
|
2017-06-02 16:02:09 +00:00
|
|
|
wfDebugLog( 'SpamBlacklist',
|
|
|
|
"Spam blacklist validator: [[$thisPageName]] ok or empty blacklist\n"
|
|
|
|
);
|
2012-01-17 06:13:46 +00:00
|
|
|
}
|
2012-01-18 23:29:37 +00:00
|
|
|
|
|
|
|
return true;
|
2012-01-17 06:13:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-07-25 14:05:13 +00:00
|
|
|
* Hook function for PageContentSaveComplete
|
2012-01-17 06:13:46 +00:00
|
|
|
* Clear local spam blacklist caches on page save.
|
|
|
|
*
|
2017-12-08 14:15:03 +00:00
|
|
|
* @param WikiPage $wikiPage
|
2017-09-01 04:57:27 +00:00
|
|
|
* @param User $user
|
|
|
|
* @param Content $content
|
|
|
|
* @param string $summary
|
|
|
|
* @param bool $isMinor
|
|
|
|
* @param bool $isWatch
|
|
|
|
* @param string $section
|
|
|
|
* @param int $flags
|
2016-01-08 21:58:59 +00:00
|
|
|
* @param Revision|null $revision
|
2017-09-01 04:57:27 +00:00
|
|
|
* @param Status $status
|
|
|
|
* @param int $baseRevId
|
2013-07-25 14:05:13 +00:00
|
|
|
*
|
2012-01-17 06:13:46 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
2018-11-02 11:54:59 +00:00
|
|
|
public static function pageSaveContent(
|
2017-12-08 14:15:03 +00:00
|
|
|
WikiPage $wikiPage,
|
2013-07-25 14:05:13 +00:00
|
|
|
User $user,
|
|
|
|
Content $content,
|
|
|
|
$summary,
|
|
|
|
$isMinor,
|
|
|
|
$isWatch,
|
|
|
|
$section,
|
|
|
|
$flags,
|
|
|
|
$revision,
|
|
|
|
Status $status,
|
|
|
|
$baseRevId
|
|
|
|
) {
|
2015-07-31 21:02:14 +00:00
|
|
|
if ( !BaseBlacklist::isLocalSource( $wikiPage->getTitle() ) ) {
|
2012-02-15 14:58:26 +00:00
|
|
|
return true;
|
2012-01-17 06:13:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This sucks because every Blacklist needs to be cleared
|
|
|
|
foreach ( BaseBlacklist::getBlacklistTypes() as $type => $class ) {
|
2015-07-31 21:02:14 +00:00
|
|
|
$blacklist = BaseBlacklist::getInstance( $type );
|
|
|
|
$blacklist->clearCache();
|
2012-01-17 06:13:46 +00:00
|
|
|
}
|
2015-07-31 21:02:14 +00:00
|
|
|
|
2016-07-22 14:02:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param UploadBase $upload
|
|
|
|
* @param User $user
|
2019-05-15 18:36:14 +00:00
|
|
|
* @param array|null $props
|
2016-07-22 14:02:31 +00:00
|
|
|
* @param string $comment
|
|
|
|
* @param string $pageText
|
|
|
|
* @param array|ApiMessage &$error
|
|
|
|
* @return bool
|
|
|
|
*/
|
2017-06-02 16:02:09 +00:00
|
|
|
public static function onUploadVerifyUpload(
|
|
|
|
UploadBase $upload,
|
|
|
|
User $user,
|
2019-05-15 18:36:14 +00:00
|
|
|
$props,
|
2017-06-02 16:02:09 +00:00
|
|
|
$comment,
|
|
|
|
$pageText,
|
|
|
|
&$error
|
|
|
|
) {
|
2016-07-22 14:02:31 +00:00
|
|
|
$title = $upload->getTitle();
|
|
|
|
|
|
|
|
// get the link from the not-yet-saved page content.
|
|
|
|
$content = ContentHandler::makeContent( $pageText, $title );
|
2018-07-11 16:34:25 +00:00
|
|
|
$parserOptions = ParserOptions::newCanonical( 'canonical' );
|
2016-07-22 14:02:31 +00:00
|
|
|
$output = $content->getParserOutput( $title, null, $parserOptions );
|
|
|
|
$links = array_keys( $output->getExternalLinks() );
|
|
|
|
|
|
|
|
// HACK: treat comment as a link if it contains anything
|
|
|
|
// that looks like it could be a URL or e-mail address.
|
|
|
|
if ( preg_match( '/\S(\.[^\s\d]{2,}|[\/@]\S)/', $comment ) ) {
|
|
|
|
$links[] = $comment;
|
|
|
|
}
|
|
|
|
if ( !$links ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-25 01:25:04 +00:00
|
|
|
$spamObj = BaseBlacklist::getSpamBlacklist();
|
2016-07-22 14:02:31 +00:00
|
|
|
$matches = $spamObj->filter( $links, $title );
|
|
|
|
|
|
|
|
if ( $matches !== false ) {
|
|
|
|
$error = new ApiMessage(
|
2019-08-01 00:27:06 +00:00
|
|
|
wfMessage( 'spam-blacklisted-link', Message::listParam( $matches ) ),
|
2016-07-22 14:02:31 +00:00
|
|
|
'spamblacklist',
|
2017-06-06 16:29:27 +00:00
|
|
|
[
|
|
|
|
'spamblacklist' => [ 'matches' => $matches ],
|
|
|
|
]
|
2016-07-22 14:02:31 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-02-02 22:12:43 +00:00
|
|
|
return true;
|
2012-01-17 06:13:46 +00:00
|
|
|
}
|
|
|
|
}
|