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