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 MediaWiki\Api\ApiBase;
16use MediaWiki\Api\ApiMain;
17use MediaWiki\JobQueue\JobQueueGroupFactory;
18use MediaWiki\Title\Title;
19use Wikimedia\IPUtils;
20use Wikimedia\ParamValidator\ParamValidator;
21
22class ApiBounceHandler extends ApiBase {
23
24    private JobQueueGroupFactory $jobQueueGroupFactory;
25
26    public function __construct(
27        ApiMain $mainModule,
28        string $moduleName,
29        JobQueueGroupFactory $jobQueueGroupFactory
30    ) {
31        parent::__construct( $mainModule, $moduleName );
32        $this->jobQueueGroupFactory = $jobQueueGroupFactory;
33    }
34
35    public function execute() {
36        $requestIP = $this->getRequest()->getIP();
37        $inRangeIP = false;
38        foreach ( $this->getConfig()->get( 'BounceHandlerInternalIPs' ) as $internalIP ) {
39            if ( IPUtils::isInRange( $requestIP, $internalIP ) ) {
40                $inRangeIP = true;
41                break;
42            }
43        }
44        if ( !$inRangeIP ) {
45            wfDebugLog( 'BounceHandler', "POST received from restricted IP $requestIP" );
46            $this->dieWithError( 'apierror-bouncehandler-internalonly', 'invalid-ip' );
47        }
48
49        $params = $this->extractRequestParams();
50
51        // Extract the wiki ID from the Verp address (also verifies the hash)
52        $bounceProcessor = new ProcessBounceWithRegex();
53        $emailHeaders = $bounceProcessor->extractHeaders( $params['email'] );
54        $to = $emailHeaders['to'] ?? '';
55        $failedUser = strlen( $to ) ? $bounceProcessor->getUserDetails( $to ) : [];
56
57        // Route the job to the wiki that the email was sent from.
58        // This way it can easily unconfirm the user's email using the User methods.
59        if ( isset( $failedUser['wikiId'] ) ) {
60            $title = Title::newFromText( 'BounceHandler Job' );
61            $job = new BounceHandlerJob( $title, $params );
62            $this->jobQueueGroupFactory->makeJobQueueGroup( $failedUser['wikiId'] )->push( $job );
63
64            $this->getResult()->addValue(
65                null,
66                $this->getModuleName(),
67                [ 'submitted' => 'job' ]
68            );
69        } else {
70            $this->getResult()->addValue(
71                null,
72                $this->getModuleName(),
73                [ 'submitted' => 'failure' ]
74            );
75        }
76
77        return true;
78    }
79
80    /**
81     * Mark the API as internal
82     *
83     * @return bool
84     */
85    public function isInternal() {
86        return true;
87    }
88
89    /** @inheritDoc */
90    public function mustBePosted() {
91        return true;
92    }
93
94    /** @inheritDoc */
95    public function isWriteMode() {
96        return true;
97    }
98
99    /** @inheritDoc */
100    public function getAllowedParams() {
101        return [
102            'email' => [
103                ParamValidator::PARAM_TYPE => 'string',
104                ParamValidator::PARAM_REQUIRED => true
105            ]
106        ];
107    }
108
109    /**
110     * @see ApiBase::getExamplesMessages()
111     * @return array
112     */
113    public function getExamplesMessages() {
114        return [
115            'action=bouncehandler&email=This%20is%20a%20test%20email'
116                => 'apihelp-bouncehandler-example-1'
117        ];
118    }
119
120    /** @inheritDoc */
121    public function getHelpUrls() {
122        return "https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:BounceHandler#API";
123    }
124
125}