Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 45 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
FlickrBlacklist | |
0.00% |
0 / 45 |
|
0.00% |
0 / 5 |
210 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
isBlacklisted | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getBlacklist | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
getPhotoIdFromUrl | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
getUserIdsFromPhotoId | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\UploadWizard; |
4 | |
5 | use IContextSource; |
6 | use MediaWiki\MediaWikiServices; |
7 | use MediaWiki\Title\Title; |
8 | use TextContent; |
9 | |
10 | /** |
11 | * Checks Flickr images against a blacklist of users |
12 | */ |
13 | class FlickrBlacklist { |
14 | /** |
15 | * Regexp to extract photo id (as match group 1) from a static image URL. |
16 | */ |
17 | private const IMAGE_URL_REGEXP = '!static\.?flickr\.com/[^/]+/([0-9]+)_!'; |
18 | |
19 | /** |
20 | * Regexp to extract photo id (as match group 1) from a photo page URL. |
21 | */ |
22 | private const PHOTO_URL_REGEXP = '!flickr\.com/(?:x/t/[^/]+/)?photos/[^/]+/([0-9]+)!'; |
23 | |
24 | /** |
25 | * An array of the blacklisted Flickr NSIDs and path_aliases. |
26 | * Used as an in-memory cache to speed successive lookups; null means not yet initialized. |
27 | * @var array|null |
28 | */ |
29 | protected static $blacklist = null; |
30 | |
31 | /** |
32 | * @var string |
33 | */ |
34 | protected $flickrApiKey; |
35 | |
36 | /** |
37 | * @var string |
38 | */ |
39 | protected $flickrApiUrl; |
40 | |
41 | /** |
42 | * Name of the wiki page which contains the NSID blacklist. |
43 | * |
44 | * The page should contain usernames (either the path_alias - the human-readable username |
45 | * in the URL - or the NSID) separated by whitespace. It is not required to contain both |
46 | * path_alias and NSID for the same user. |
47 | * |
48 | * Lines starting with # are ignored. |
49 | * @var string |
50 | */ |
51 | protected $flickrBlacklistPage; |
52 | |
53 | /** |
54 | * @var IContextSource |
55 | */ |
56 | protected $context; |
57 | |
58 | /** |
59 | * Sets options based on a config array such as Config::getConfig(). |
60 | * @param array $options an array with 'flickrApiKey', 'flickrApiUrl' and |
61 | * 'flickrBlacklistPage' keys |
62 | * @param IContextSource $context |
63 | */ |
64 | public function __construct( array $options, IContextSource $context ) { |
65 | $this->flickrApiKey = $options['flickrApiKey']; |
66 | $this->flickrApiUrl = $options['flickrApiUrl']; |
67 | $this->flickrBlacklistPage = $options['flickrBlacklistPage']; |
68 | $this->context = $context; |
69 | } |
70 | |
71 | /** |
72 | * @param string $url |
73 | * @return bool |
74 | */ |
75 | public function isBlacklisted( $url ) { |
76 | $blacklist = $this->getBlacklist(); |
77 | |
78 | $flickrPhotoId = $this->getPhotoIdFromUrl( $url ); |
79 | if ( $flickrPhotoId ) { |
80 | $userIds = $this->getUserIdsFromPhotoId( $flickrPhotoId ); |
81 | return (bool)array_intersect( $userIds, $blacklist ); |
82 | } |
83 | // FIXME should we tell the user we did not recognize the URL? |
84 | return false; |
85 | } |
86 | |
87 | /** |
88 | * Returns the blacklist, which is a non-associative array of user NSIDs and path_aliases |
89 | * (the name name which can be seen in the pretty URL). For a given user, usually only one |
90 | * of the NSID and the path_alias will be present; it is the responsibility of the consumers |
91 | * of the blacklist to check it against both. |
92 | * @return array |
93 | */ |
94 | public function getBlacklist() { |
95 | if ( self::$blacklist === null ) { |
96 | self::$blacklist = []; |
97 | if ( $this->flickrBlacklistPage ) { |
98 | $title = Title::newFromText( $this->flickrBlacklistPage ); |
99 | $page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $title ); |
100 | $content = $page->getContent(); |
101 | $text = ( $content instanceof TextContent ) ? $content->getText() : ''; |
102 | $text = preg_replace( '/^\s*#.*$/m', '', $text ); |
103 | preg_match_all( '/\S+/', $text, $match ); |
104 | self::$blacklist = $match[0]; |
105 | } |
106 | } |
107 | return self::$blacklist; |
108 | } |
109 | |
110 | /** |
111 | * Takes a Flickr photo page URL or a direct image URL, returns photo id (or false on failure). |
112 | * @param string $url |
113 | * @return string|bool |
114 | */ |
115 | protected function getPhotoIdFromUrl( $url ) { |
116 | if ( preg_match( self::IMAGE_URL_REGEXP, $url, $matches ) ) { |
117 | return $matches[1]; |
118 | } elseif ( preg_match( self::PHOTO_URL_REGEXP, $url, $matches ) ) { |
119 | return $matches[1]; |
120 | } else { |
121 | return false; |
122 | } |
123 | } |
124 | |
125 | /** |
126 | * Takes a photo ID, returns owner's NSID and path_alias |
127 | * (the username which appears in the URL), if available. |
128 | * @param string $flickrPhotoId |
129 | * @return array an array containing the NSID first and the path_alias second. The path_alias |
130 | * is not guaranteed to exist, in which case the array will have a single item; |
131 | * if there is no such photo (or some other error happened), the array will be empty. |
132 | */ |
133 | protected function getUserIdsFromPhotoId( $flickrPhotoId ) { |
134 | $userIds = []; |
135 | $params = [ |
136 | 'postData' => [ |
137 | 'method' => 'flickr.photos.getInfo', |
138 | 'api_key' => $this->flickrApiKey, |
139 | 'photo_id' => $flickrPhotoId, |
140 | 'format' => 'json', |
141 | 'nojsoncallback' => 1, |
142 | ], |
143 | ]; |
144 | $response = MediaWikiServices::getInstance()->getHttpRequestFactory() |
145 | ->post( $this->flickrApiUrl, $params, __METHOD__ ); |
146 | if ( $response !== false ) { |
147 | $response = json_decode( $response, true ); |
148 | } |
149 | if ( isset( $response['photo']['owner']['nsid'] ) ) { |
150 | $userIds[] = $response['photo']['owner']['nsid']; |
151 | } |
152 | // what Flickr calls 'username' can change at any time and so is worthless for blacklisting |
153 | // path_alias is the username in the pretty URL; once set, it cannot be changed. |
154 | if ( isset( $response['photo']['owner']['path_alias'] ) ) { |
155 | $userIds[] = $response['photo']['owner']['path_alias']; |
156 | } |
157 | return $userIds; |
158 | } |
159 | } |