Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
12.96% |
14 / 108 |
|
11.11% |
1 / 9 |
CRAP | |
0.00% |
0 / 1 |
GlobalBlockingHooks | |
12.96% |
14 / 108 |
|
11.11% |
1 / 9 |
507.66 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
onGetUserBlock | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
20 | |||
onUserIsBlockedGlobally | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
onSpecialPasswordResetOnSubmit | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
onGetBlockErrorMessageKey | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
5.03 | |||
onOtherBlockLogLink | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
onSpecialContributionsBeforeMainOutput | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
12 | |||
onContributionsToolLinks | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
42 | |||
onGetLogTypesOnUser | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\GlobalBlocking; |
4 | |
5 | use CentralIdLookup; |
6 | use LogicException; |
7 | use MediaWiki\Block\AbstractBlock; |
8 | use MediaWiki\Block\Block; |
9 | use MediaWiki\Block\CompositeBlock; |
10 | use MediaWiki\Block\Hook\GetUserBlockHook; |
11 | use MediaWiki\CommentFormatter\CommentFormatter; |
12 | use MediaWiki\Config\Config; |
13 | use MediaWiki\Extension\GlobalBlocking\Services\GlobalBlockingLinkBuilder; |
14 | use MediaWiki\Extension\GlobalBlocking\Special\GlobalBlockListPager; |
15 | use MediaWiki\Hook\ContributionsToolLinksHook; |
16 | use MediaWiki\Hook\GetBlockErrorMessageKeyHook; |
17 | use MediaWiki\Hook\GetLogTypesOnUserHook; |
18 | use MediaWiki\Hook\OtherBlockLogLinkHook; |
19 | use MediaWiki\Hook\SpecialContributionsBeforeMainOutputHook; |
20 | use MediaWiki\Html\Html; |
21 | use MediaWiki\Permissions\PermissionManager; |
22 | use MediaWiki\SpecialPage\SpecialPage; |
23 | use MediaWiki\Title\Title; |
24 | use MediaWiki\User\Hook\SpecialPasswordResetOnSubmitHook; |
25 | use MediaWiki\User\Hook\UserIsBlockedGloballyHook; |
26 | use MediaWiki\User\User; |
27 | use Message; |
28 | use RequestContext; |
29 | use Wikimedia\IPUtils; |
30 | |
31 | /** |
32 | * MediaWiki hook handlers for the GlobalBlocking extension |
33 | * |
34 | * @license GPL-2.0-or-later |
35 | */ |
36 | class GlobalBlockingHooks implements |
37 | GetUserBlockHook, |
38 | UserIsBlockedGloballyHook, |
39 | SpecialPasswordResetOnSubmitHook, |
40 | GetBlockErrorMessageKeyHook, |
41 | OtherBlockLogLinkHook, |
42 | SpecialContributionsBeforeMainOutputHook, |
43 | GetLogTypesOnUserHook, |
44 | ContributionsToolLinksHook |
45 | { |
46 | private PermissionManager $permissionManager; |
47 | private Config $config; |
48 | private CommentFormatter $commentFormatter; |
49 | private CentralIdLookup $lookup; |
50 | private GlobalBlockingLinkBuilder $globalBlockLinkBuilder; |
51 | |
52 | /** |
53 | * @param PermissionManager $permissionManager |
54 | * @param Config $mainConfig |
55 | * @param CommentFormatter $commentFormatter |
56 | * @param CentralIdLookup $lookup |
57 | * @param GlobalBlockingLinkBuilder $globalBlockLinkBuilder |
58 | */ |
59 | public function __construct( |
60 | PermissionManager $permissionManager, |
61 | Config $mainConfig, |
62 | CommentFormatter $commentFormatter, |
63 | CentralIdLookup $lookup, |
64 | GlobalBlockingLinkBuilder $globalBlockLinkBuilder |
65 | ) { |
66 | $this->permissionManager = $permissionManager; |
67 | $this->config = $mainConfig; |
68 | $this->commentFormatter = $commentFormatter; |
69 | $this->lookup = $lookup; |
70 | $this->globalBlockLinkBuilder = $globalBlockLinkBuilder; |
71 | } |
72 | |
73 | /** |
74 | * Add a global block. If there are any existing blocks, add |
75 | * the global block into a CompositeBlock. |
76 | * |
77 | * @param User $user |
78 | * @param string|null $ip null unless we're checking the session user |
79 | * @param AbstractBlock|null &$block |
80 | * @return bool |
81 | */ |
82 | public function onGetUserBlock( $user, $ip, &$block ) { |
83 | if ( !$this->config->get( 'ApplyGlobalBlocks' ) ) { |
84 | return true; |
85 | } |
86 | |
87 | $globalBlock = GlobalBlocking::getUserBlock( $user, $ip ); |
88 | if ( !$globalBlock ) { |
89 | return true; |
90 | } |
91 | |
92 | if ( !$block ) { |
93 | $block = $globalBlock; |
94 | return true; |
95 | } |
96 | |
97 | // User is locally blocked and globally blocked. We need a CompositeBlock. |
98 | $allBlocks = $block->toArray(); |
99 | $allBlocks[] = $globalBlock; |
100 | $block = new CompositeBlock( [ |
101 | 'address' => $ip ?? $user->getName(), |
102 | 'reason' => new Message( 'blockedtext-composite-reason' ), |
103 | 'originalBlocks' => $allBlocks, |
104 | ] ); |
105 | return true; |
106 | } |
107 | |
108 | /** |
109 | * @param User $user |
110 | * @param string $ip |
111 | * @param bool &$blocked |
112 | * @param AbstractBlock|null &$block |
113 | * |
114 | * @return bool |
115 | */ |
116 | public function onUserIsBlockedGlobally( $user, $ip, &$blocked, &$block ) { |
117 | $block = GlobalBlocking::getUserBlock( $user, $ip ); |
118 | if ( $block !== null ) { |
119 | $blocked = true; |
120 | return false; |
121 | } |
122 | return true; |
123 | } |
124 | |
125 | /** |
126 | * @param array &$users |
127 | * @param array $data |
128 | * @param string &$error |
129 | * |
130 | * @return bool |
131 | */ |
132 | public function onSpecialPasswordResetOnSubmit( &$users, $data, &$error ) { |
133 | $requestContext = RequestContext::getMain(); |
134 | |
135 | if ( GlobalBlocking::getUserBlockErrors( |
136 | $requestContext->getUser(), |
137 | $requestContext->getRequest()->getIP() |
138 | ) ) { |
139 | $error = 'globalblocking-blocked-nopassreset'; |
140 | return false; |
141 | } |
142 | return true; |
143 | } |
144 | |
145 | /** |
146 | * @param Block $block |
147 | * @param string &$key |
148 | * |
149 | * @return bool |
150 | */ |
151 | public function onGetBlockErrorMessageKey( Block $block, string &$key ) { |
152 | if ( $block instanceof GlobalBlock ) { |
153 | if ( $block->getXff() ) { |
154 | $key = 'globalblocking-blockedtext-xff'; |
155 | } elseif ( IPUtils::isValid( $block->getTargetName() ) ) { |
156 | $key = 'globalblocking-blockedtext-ip'; |
157 | } elseif ( IPUtils::isValidRange( $block->getTargetName() ) ) { |
158 | $key = 'globalblocking-blockedtext-range'; |
159 | } else { |
160 | $key = 'globalblocking-blockedtext-user'; |
161 | } |
162 | return false; |
163 | } |
164 | return true; |
165 | } |
166 | |
167 | /** |
168 | * Creates a link to the global block log |
169 | * @param array &$msg Message with a link to the global block log |
170 | * @param string $ip The IP address to be checked |
171 | * |
172 | * @return bool true |
173 | */ |
174 | public function onOtherBlockLogLink( &$msg, $ip ) { |
175 | // Fast return if it is a username. IP addresses can be blocked only. |
176 | if ( !IPUtils::isIPAddress( $ip ) ) { |
177 | return true; |
178 | } |
179 | |
180 | $block = GlobalBlocking::getGlobalBlockingBlock( $ip, true ); |
181 | if ( !$block ) { |
182 | // Fast return if not globally blocked |
183 | return true; |
184 | } |
185 | |
186 | $msg[] = Html::rawElement( |
187 | 'span', |
188 | [ 'class' => 'mw-globalblock-loglink plainlinks' ], |
189 | wfMessage( 'globalblocking-loglink', $ip )->parse() |
190 | ); |
191 | return true; |
192 | } |
193 | |
194 | /** |
195 | * Show global block notice on Special:Contributions. |
196 | * @param int $userId |
197 | * @param User $user |
198 | * @param SpecialPage $sp |
199 | * |
200 | * @return bool |
201 | */ |
202 | public function onSpecialContributionsBeforeMainOutput( |
203 | $userId, $user, $sp |
204 | ) { |
205 | $name = $user->getName(); |
206 | if ( !IPUtils::isIPAddress( $name ) ) { |
207 | return true; |
208 | } |
209 | |
210 | $block = GlobalBlocking::getGlobalBlockingBlock( $name, true ); |
211 | |
212 | if ( $block ) { |
213 | $conds = GlobalBlocking::getRangeCondition( $block->gb_address ); |
214 | $pager = new GlobalBlockListPager( |
215 | $sp->getContext(), |
216 | $conds, |
217 | $sp->getLinkRenderer(), |
218 | $this->commentFormatter, |
219 | $this->lookup, |
220 | $this->globalBlockLinkBuilder |
221 | ); |
222 | $body = $pager->formatRow( $block ); |
223 | |
224 | $out = $sp->getOutput(); |
225 | $out->addHTML( |
226 | Html::warningBox( |
227 | $sp->msg( 'globalblocking-contribs-notice', $name )->parseAsBlock() . |
228 | Html::rawElement( |
229 | 'ul', |
230 | [ 'class' => 'mw-logevent-loglines' ], |
231 | $body |
232 | ), |
233 | 'mw-warning-with-logexcerpt' |
234 | ) |
235 | ); |
236 | } |
237 | |
238 | return true; |
239 | } |
240 | |
241 | /** |
242 | * Adds a link on Special:Contributions to Special:GlobalBlock for privileged users. |
243 | * @param int $id User ID |
244 | * @param Title $title User page title |
245 | * @param array &$tools Tool links |
246 | * @param SpecialPage $sp Special page |
247 | * @return bool|void |
248 | */ |
249 | public function onContributionsToolLinks( |
250 | $id, $title, &$tools, $sp |
251 | ) { |
252 | $user = $sp->getUser(); |
253 | $linkRenderer = $sp->getLinkRenderer(); |
254 | $ip = $title->getText(); |
255 | |
256 | if ( IPUtils::isIPAddress( $ip ) ) { |
257 | if ( IPUtils::isValidRange( $ip ) ) { |
258 | $target = IPUtils::sanitizeRange( $ip ); |
259 | } else { |
260 | $target = IPUtils::sanitizeIP( $ip ); |
261 | } |
262 | if ( $target === null ) { |
263 | throw new LogicException( 'IPUtils::sanitizeIP returned null for a valid IP' ); |
264 | } |
265 | if ( $this->permissionManager->userHasRight( $user, 'globalblock' ) ) { |
266 | if ( GlobalBlocking::getGlobalBlockId( $ip ) === 0 ) { |
267 | $tools['globalblock'] = $linkRenderer->makeKnownLink( |
268 | SpecialPage::getTitleFor( 'GlobalBlock', $target ), |
269 | $sp->msg( 'globalblocking-contribs-block' )->text() |
270 | ); |
271 | } else { |
272 | $tools['globalblock'] = $linkRenderer->makeKnownLink( |
273 | SpecialPage::getTitleFor( 'GlobalBlock', $target ), |
274 | $sp->msg( 'globalblocking-contribs-modify' )->text() |
275 | ); |
276 | |
277 | $tools['globalunblock'] = $linkRenderer->makeKnownLink( |
278 | SpecialPage::getTitleFor( 'RemoveGlobalBlock', $target ), |
279 | $sp->msg( 'globalblocking-contribs-remove' )->text() |
280 | ); |
281 | } |
282 | } |
283 | } |
284 | } |
285 | |
286 | /** |
287 | * So users can just type in a username for target and it'll work |
288 | * @param array &$types |
289 | * @return bool |
290 | */ |
291 | public function onGetLogTypesOnUser( &$types ) { |
292 | $types[] = 'gblblock'; |
293 | |
294 | return true; |
295 | } |
296 | } |