Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.33% covered (warning)
73.33%
33 / 45
37.50% covered (danger)
37.50%
3 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiBounceHandler
73.33% covered (warning)
73.33%
33 / 45
37.50% covered (danger)
37.50%
3 / 8
16.20
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 execute
82.76% covered (warning)
82.76%
24 / 29
0.00% covered (danger)
0.00%
0 / 1
6.18
 isInternal
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 mustBePosted
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isWriteMode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllowedParams
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getHelpUrls
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Class ApiBounceHandler
4 *
5 * API to handle e-mail bounces
6 *
7 * @file
8 * @ingroup API
9 * @author Tony Thomas, Kunal Mehta, Jeff Green
10 * @license GPL-2.0-or-later
11 */
12
13namespace MediaWiki\Extension\BounceHandler;
14
15use ApiBase;
16use ApiMain;
17use MediaWiki\JobQueue\JobQueueGroupFactory;
18use MediaWiki\Title\Title;
19use Wikimedia\IPUtils;
20use Wikimedia\ParamValidator\ParamValidator;
21
22class ApiBounceHandler extends ApiBase {
23
24    /** @var JobQueueGroupFactory */
25    private $jobQueueGroupFactory;
26
27    /**
28     * @param ApiMain $mainModule
29     * @param string $moduleName
30     * @param JobQueueGroupFactory $jobQueueGroupFactory
31     */
32    public function __construct(
33        ApiMain $mainModule,
34        $moduleName,
35        JobQueueGroupFactory $jobQueueGroupFactory
36    ) {
37        parent::__construct( $mainModule, $moduleName );
38        $this->jobQueueGroupFactory = $jobQueueGroupFactory;
39    }
40
41    public function execute() {
42        $requestIP = $this->getRequest()->getIP();
43        $inRangeIP = false;
44        foreach ( $this->getConfig()->get( 'BounceHandlerInternalIPs' ) as $internalIP ) {
45            if ( IPUtils::isInRange( $requestIP, $internalIP ) ) {
46                $inRangeIP = true;
47                break;
48            }
49        }
50        if ( !$inRangeIP ) {
51            wfDebugLog( 'BounceHandler', "POST received from restricted IP $requestIP" );
52            $this->dieWithError( 'apierror-bouncehandler-internalonly', 'invalid-ip' );
53        }
54
55        $params = $this->extractRequestParams();
56
57        // Extract the wiki ID from the Verp address (also verifies the hash)
58        $bounceProcessor = new ProcessBounceWithRegex();
59        $emailHeaders = $bounceProcessor->extractHeaders( $params['email'] );
60        $to = $emailHeaders['to'] ?? '';
61        $failedUser = strlen( $to ) ? $bounceProcessor->getUserDetails( $to ) : [];
62
63        // Route the job to the wiki that the email was sent from.
64        // This way it can easily unconfirm the user's email using the User methods.
65        if ( isset( $failedUser['wikiId'] ) ) {
66            $title = Title::newFromText( 'BounceHandler Job' );
67            $job = new BounceHandlerJob( $title, $params );
68            $this->jobQueueGroupFactory->makeJobQueueGroup( $failedUser['wikiId'] )->push( $job );
69
70            $this->getResult()->addValue(
71                null,
72                $this->getModuleName(),
73                [ 'submitted' => 'job' ]
74            );
75        } else {
76            $this->getResult()->addValue(
77                null,
78                $this->getModuleName(),
79                [ 'submitted' => 'failure' ]
80            );
81        }
82
83        return true;
84    }
85
86    /**
87     * Mark the API as internal
88     *
89     * @return bool
90     */
91    public function isInternal() {
92        return true;
93    }
94
95    /** @inheritDoc */
96    public function mustBePosted() {
97        return true;
98    }
99
100    /** @inheritDoc */
101    public function isWriteMode() {
102        return true;
103    }
104
105    /** @inheritDoc */
106    public function getAllowedParams() {
107        return [
108            'email' => [
109                ParamValidator::PARAM_TYPE => 'string',
110                ParamValidator::PARAM_REQUIRED => true
111            ]
112        ];
113    }
114
115    /**
116     * @see ApiBase::getExamplesMessages()
117     * @return array
118     */
119    public function getExamplesMessages() {
120        return [
121            'action=bouncehandler&email=This%20is%20a%20test%20email'
122                => 'apihelp-bouncehandler-example-1'
123        ];
124    }
125
126    /** @inheritDoc */
127    public function getHelpUrls() {
128        return "https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:BounceHandler#API";
129    }
130
131}