Index: trunk/extensions/FlaggedRevs/frontend/specialpages/actions/RevisionReview_body.php |
— | — | @@ -62,6 +62,8 @@ |
63 | 63 | $form->setValidatedParams( $request->getVal( 'validatedParams' ) ); |
64 | 64 | # Conflict handling |
65 | 65 | $form->setLastChangeTime( $request->getVal( 'changetime' ) ); |
| 66 | + # Session key |
| 67 | + $form->setSessionKey( $request->getSessionData( 'wsFlaggedRevsKey' ) ); |
66 | 68 | # Tag values |
67 | 69 | foreach ( FlaggedRevs::getTags() as $tag ) { |
68 | 70 | # This can be NULL if we uncheck a checkbox |
— | — | @@ -188,7 +190,7 @@ |
189 | 191 | } |
190 | 192 | |
191 | 193 | public static function AjaxReview( /*$args...*/ ) { |
192 | | - global $wgUser, $wgOut; |
| 194 | + global $wgUser, $wgOut, $wgRequest; |
193 | 195 | |
194 | 196 | $args = func_get_args(); |
195 | 197 | if ( wfReadOnly() ) { |
— | — | @@ -263,6 +265,7 @@ |
264 | 266 | return '<err#>' . wfMsgExt( 'notargettext', 'parseinline' ); |
265 | 267 | } |
266 | 268 | $form->setPage( $title ); |
| 269 | + $form->setSessionKey( $wgRequest->getSessionData( 'wsFlaggedRevsKey' ) ); |
267 | 270 | |
268 | 271 | $status = $form->ready(); // all params loaded |
269 | 272 | # Check session via user token |
Index: trunk/extensions/FlaggedRevs/frontend/RevisionReviewFormUI.php |
— | — | @@ -231,8 +231,9 @@ |
232 | 232 | $form .= Html::hidden( 'imageParams', $imageParams ) . "\n"; |
233 | 233 | $form .= Html::hidden( 'fileVersion', $fileVersion ) . "\n"; |
234 | 234 | # Special token to discourage fiddling... |
| 235 | + $key = $this->request->getSessionData( 'wsFlaggedRevsKey' ); |
235 | 236 | $checkCode = RevisionReviewForm::validationKey( |
236 | | - $templateParams, $imageParams, $fileVersion, $revId |
| 237 | + $templateParams, $imageParams, $fileVersion, $revId, $key |
237 | 238 | ); |
238 | 239 | $form .= Html::hidden( 'validatedParams', $checkCode ) . "\n"; |
239 | 240 | |
Index: trunk/extensions/FlaggedRevs/backend/FlaggedRevs.hooks.php |
— | — | @@ -922,6 +922,19 @@ |
923 | 923 | return true; |
924 | 924 | } |
925 | 925 | |
| 926 | + public static function setSessionKey( User $user ) { |
| 927 | + global $wgRequest; |
| 928 | + if ( $user->isAllowed( 'review' ) ) { |
| 929 | + $key = $wgRequest->getSessionData( 'wsFlaggedRevsKey' ); |
| 930 | + if ( $key === null ) { // should catch login |
| 931 | + $key = User::generateToken( $user->getId() ); |
| 932 | + // Temporary secret key attached to this session |
| 933 | + $this->request->setSessionData( 'wsFlaggedRevsKey', $key ); |
| 934 | + } |
| 935 | + } |
| 936 | + return true; |
| 937 | + } |
| 938 | + |
926 | 939 | public static function stableDumpQuery( array &$tables, array &$opts, array &$join ) { |
927 | 940 | $namespaces = FlaggedRevs::getReviewNamespaces(); |
928 | 941 | if ( $namespaces ) { |
Index: trunk/extensions/FlaggedRevs/api/actions/ApiReview.php |
— | — | @@ -84,9 +84,7 @@ |
85 | 85 | $form->setTemplateParams( $templateParams ); |
86 | 86 | $form->setFileParams( $imageParams ); |
87 | 87 | $form->setFileVersion( $fileParam ); |
88 | | - $key = RevisionReviewForm::validationKey( |
89 | | - $templateParams, $imageParams, $fileParam, $revid ); |
90 | | - $form->setValidatedParams( $key ); # always OK |
| 88 | + $form->bypassValidationKey(); // always OK; uses current templates/files |
91 | 89 | } |
92 | 90 | $status = $form->ready(); // all params set |
93 | 91 | |
Index: trunk/extensions/FlaggedRevs/business/RevisionReviewForm.php |
— | — | @@ -23,6 +23,9 @@ |
24 | 24 | protected $oldFrev = null; # Prior FlaggedRevision for Rev with ID $oldid |
25 | 25 | protected $oldFlags = array(); # Prior flags for Rev with ID $oldid |
26 | 26 | |
| 27 | + protected $sessionKey = ''; # User session key |
| 28 | + protected $skipValidationKey = false; # Skip validatedParams check |
| 29 | + |
27 | 30 | protected function initialize() { |
28 | 31 | foreach ( FlaggedRevs::getTags() as $tag ) { |
29 | 32 | $this->dims[$tag] = 0; // default to "inadequate" |
— | — | @@ -124,6 +127,14 @@ |
125 | 128 | $this->trySet( $this->dims[$tag], (int)$value ); |
126 | 129 | } |
127 | 130 | |
| 131 | + public function setSessionKey( $sessionId ) { |
| 132 | + $this->sessionKey = $sessionId; |
| 133 | + } |
| 134 | + |
| 135 | + public function bypassValidationKey() { |
| 136 | + $this->skipValidationKey = true; |
| 137 | + } |
| 138 | + |
128 | 139 | /** |
129 | 140 | * Check that a target is given (e.g. from GET/POST request) |
130 | 141 | * @return mixed (true on success, error string on failure) |
— | — | @@ -190,10 +201,13 @@ |
191 | 202 | return 'review_too_low'; |
192 | 203 | } |
193 | 204 | # Special token to discourage fiddling with templates/files... |
194 | | - $k = self::validationKey( |
195 | | - $this->templateParams, $this->imageParams, $this->fileVersion, $this->oldid ); |
196 | | - if ( $this->validatedParams !== $k ) { |
197 | | - return 'review_bad_key'; |
| 205 | + if ( !$this->skipValidationKey ) { |
| 206 | + $k = self::validationKey( |
| 207 | + $this->templateParams, $this->imageParams, $this->fileVersion, |
| 208 | + $this->oldid, $this->sessionKey ); |
| 209 | + if ( $this->validatedParams !== $k ) { |
| 210 | + return 'review_bad_key'; |
| 211 | + } |
198 | 212 | } |
199 | 213 | # Sanity check tags |
200 | 214 | if ( !FlaggedRevs::flagsAreValid( $this->dims ) ) { |
— | — | @@ -464,26 +478,27 @@ |
465 | 479 | } |
466 | 480 | |
467 | 481 | /** |
468 | | - * Get a validation key from versioning metadata |
| 482 | + * Get a validation key from template/file versioning metadata |
469 | 483 | * @param string $tmpP |
470 | 484 | * @param string $imgP |
471 | 485 | * @param string $imgV |
472 | 486 | * @param integer $rid rev ID |
| 487 | + * @param string $sessKey Session key |
473 | 488 | * @return string |
474 | 489 | */ |
475 | | - public static function validationKey( $tmpP, $imgP, $imgV, $rid ) { |
| 490 | + public static function validationKey( $tmpP, $imgP, $imgV, $rid, $sessKey ) { |
476 | 491 | global $wgSecretKey, $wgProxyKey; |
477 | | - $key = $wgSecretKey ? $wgSecretKey : $wgProxyKey; // fall back to $wgProxyKey |
478 | | - $p = md5( $key . $imgP . $tmpP . $rid . $imgV ); |
479 | | - return $p; |
| 492 | + $key = md5( $wgSecretKey ? $wgSecretKey : $wgProxyKey ); // fall back to $wgProxyKey |
| 493 | + $keyBits = $key[3] . $key[9] . $key[13] . $key[19] . $key[26]; |
| 494 | + return md5( "{$imgP}{$tmpP}{$imgV}{$rid}{$sessKey}{$keyBits}" ); |
480 | 495 | } |
481 | 496 | |
482 | 497 | /** |
483 | 498 | * Update rc_patrolled fields in recent changes after (un)accepting a rev. |
484 | 499 | * This maintains the patrolled <=> reviewed relationship for reviewable namespaces. |
485 | | - * |
| 500 | + * |
486 | 501 | * RecentChange should only be passed in when an RC item is saved. |
487 | | - * |
| 502 | + * |
488 | 503 | * @param $rev Revision|RecentChange |
489 | 504 | * @param $patrol string "patrol" or "unpatrol" |
490 | 505 | * @param $srev FlaggedRevsion|null The new stable version |
Index: trunk/extensions/FlaggedRevs/FlaggedRevs.setup.php |
— | — | @@ -213,6 +213,7 @@ |
214 | 214 | $wgHooks['getUserPermissionsErrors'][] = 'FlaggedRevsHooks::onUserCan'; |
215 | 215 | # Implicit autoreview rights group |
216 | 216 | $wgHooks['AutopromoteCondition'][] = 'FlaggedRevsHooks::checkAutoPromoteCond'; |
| 217 | + $wgHooks['UserLoadAfterLoadFromSession'][] = 'FlaggedRevsHooks::setSessionKey'; |
217 | 218 | |
218 | 219 | # Stable dump hook |
219 | 220 | $wgHooks['WikiExporter::dumpStableQuery'][] = 'FlaggedRevsHooks::stableDumpQuery'; |