Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 48 |
|
0.00% |
0 / 2 |
CRAP | |
0.00% |
0 / 1 |
BlockUtils | |
0.00% |
0 / 48 |
|
0.00% |
0 / 2 |
132 | |
0.00% |
0 / 1 |
getBlockErrorMsgs | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
20 | |||
logBlockedEditAttempt | |
0.00% |
0 / 34 |
|
0.00% |
0 / 1 |
56 |
1 | <?php |
2 | |
3 | namespace WikimediaEvents; |
4 | |
5 | use MediaWiki\Block\Block; |
6 | use MediaWiki\Context\RequestContext; |
7 | use MediaWiki\Extension\EventLogging\EventLogging; |
8 | use MediaWiki\MainConfigNames; |
9 | use MediaWiki\MediaWikiServices; |
10 | use MediaWiki\Message\Message; |
11 | use MediaWiki\Title\Title; |
12 | use MediaWiki\User\User; |
13 | |
14 | class BlockUtils { |
15 | // Possible block error keys from Block\BlockErrorFormatter::getBlockErrorMessageKey() |
16 | public const LOCAL_ERROR_KEYS = [ |
17 | 'blockedtext', |
18 | 'autoblockedtext', |
19 | 'blockedtext-partial', |
20 | 'systemblockedtext', |
21 | 'blockedtext-composite' |
22 | ]; |
23 | // Possible block error keys from GlobalBlocking extension |
24 | public const GLOBAL_ERROR_KEYS = [ |
25 | 'globalblocking-blockedtext-ip', |
26 | 'globalblocking-blockedtext-range', |
27 | 'globalblocking-blockedtext-xff', |
28 | 'globalblocking-blockedtext-user', |
29 | 'globalblocking-blockedtext-autoblock', |
30 | 'globalblocking-blockedtext-autoblock-xff', |
31 | // WikimediaMessages versions |
32 | 'wikimedia-globalblocking-blockedtext-ip', |
33 | 'wikimedia-globalblocking-blockedtext-range', |
34 | 'wikimedia-globalblocking-blockedtext-xff', |
35 | 'wikimedia-globalblocking-blockedtext-user', |
36 | 'wikimedia-globalblocking-blockedtext-autoblock', |
37 | 'wikimedia-globalblocking-blockedtext-autoblock-xff', |
38 | ]; |
39 | |
40 | /** |
41 | * Build error messages for error keys |
42 | * |
43 | * @param array[] $errors from PermissionManager getPermissionErrors |
44 | * @return array<string, Message[]> |
45 | */ |
46 | public static function getBlockErrorMsgs( $errors ) { |
47 | $blockedErrorMsgs = $globalBlockedErrorMsgs = []; |
48 | foreach ( $errors as $error ) { |
49 | $errorMsg = Message::newFromSpecifier( $error ); |
50 | $errorKey = $errorMsg->getKey(); |
51 | if ( in_array( $errorKey, self::LOCAL_ERROR_KEYS, true ) ) { |
52 | $blockedErrorMsgs[] = $errorMsg; |
53 | } elseif ( in_array( $errorKey, self::GLOBAL_ERROR_KEYS, true ) ) { |
54 | $globalBlockedErrorMsgs[] = $errorMsg; |
55 | } |
56 | } |
57 | $allErrorMsgs = array_merge( $blockedErrorMsgs, $globalBlockedErrorMsgs ); |
58 | |
59 | return [ |
60 | 'local' => $blockedErrorMsgs, |
61 | 'global' => $globalBlockedErrorMsgs, |
62 | 'all' => $allErrorMsgs, |
63 | ]; |
64 | } |
65 | |
66 | /** |
67 | * Log a blocked edit attempt |
68 | * |
69 | * @param User $user |
70 | * @param Title $title |
71 | * @param string $interface |
72 | * @param string $platform |
73 | */ |
74 | public static function logBlockedEditAttempt( $user, $title, $interface, $platform ) { |
75 | // Prefer the local block over the global one if both are set. This is |
76 | // somewhat arbitrary, but is consistent with account creation block |
77 | // logging. |
78 | $local = MediaWikiServices::getInstance()->getPermissionManager()->isBlockedFrom( $user, $title, true ); |
79 | if ( $local ) { |
80 | $block = $user->getBlock(); |
81 | } else { |
82 | $block = $user->getGlobalBlock(); |
83 | } |
84 | |
85 | if ( !$block ) { |
86 | return; |
87 | } |
88 | |
89 | $rawExpiry = $block->getExpiry(); |
90 | if ( wfIsInfinity( $rawExpiry ) ) { |
91 | $expiry = 'infinity'; |
92 | } else { |
93 | $expiry = wfTimestamp( TS_ISO_8601, $rawExpiry ); |
94 | } |
95 | |
96 | $request = RequestContext::getMain()->getRequest(); |
97 | // Avoid accessing the service and its dependencies if we can by checking |
98 | // first if we can get the country code from the GeoIP cookie. |
99 | $countryCode = WikimediaEventsCountryCodeLookup::getFromCookie( $request ); |
100 | if ( !$countryCode ) { |
101 | /** @var WikimediaEventsCountryCodeLookup $countryCodeLookup */ |
102 | $countryCodeLookup = MediaWikiServices::getInstance()->get( 'WikimediaEventsCountryCodeLookup' ); |
103 | $countryCode = $countryCodeLookup->getFromGeoIP( $request ); |
104 | } |
105 | |
106 | $event = [ |
107 | '$schema' => '/analytics/mediawiki/editattemptsblocked/1.0.0', |
108 | 'block_id' => json_encode( $block->getIdentifier() ), |
109 | // @phan-suppress-next-line PhanTypeMismatchDimFetchNullable |
110 | 'block_type' => Block::BLOCK_TYPES[ $block->getType() ] ?? 'other', |
111 | 'block_expiry' => $expiry, |
112 | 'block_scope' => $local ? 'local' : 'global', |
113 | 'platform' => $platform, |
114 | 'interface' => $interface, |
115 | 'country_code' => WikimediaEventsCountryCodeLookup::getCountryCodeFormattedForEvent( $countryCode ), |
116 | // http.client_ip is handled by eventgate-wikimedia |
117 | 'database' => MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::DBname ), |
118 | 'page_id' => $title->getId(), |
119 | 'page_namespace' => $title->getNamespace(), |
120 | 'rev_id' => $title->getLatestRevID(), |
121 | 'performer' => [ |
122 | 'user_id' => $user->getId(), |
123 | 'user_edit_count' => $user->getEditCount() ?: 0, |
124 | ], |
125 | ]; |
126 | EventLogging::submit( 'mediawiki.editattempt_block', $event ); |
127 | } |
128 | |
129 | } |