MarkAHershberger has uploaded a new change for review. (
https://gerrit.wikimedia.org/r/398520 )
Change subject: Clean up formatting, bring code up to modernish standards
......................................................................
Clean up formatting, bring code up to modernish standards
* Take functions out of the global context.
* Newish array notation.
* Documentation for every function.
* Line length.
* Consolidate checking of $wgNamespacePermissionLockdown.
Change-Id: I319a09a2dad1178ea3470949e4928e9a665cc8c6
---
M Lockdown.php
1 file changed, 230 insertions(+), 170 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Lockdown
refs/changes/20/398520/1
diff --git a/Lockdown.php b/Lockdown.php
index 9ba1af0..1db1a2a 100644
--- a/Lockdown.php
+++ b/Lockdown.php
@@ -1,220 +1,280 @@
<?php
/**
- * Lockdown extension - implements restrictions on individual namespaces and
special pages.
+ * Lockdown extension - implements restrictions on individual
+ * namespaces and special pages.
*
* @file
* @ingroup Extensions
* @author Daniel Kinzler, brightbyte.de
- * @copyright © 2007 Daniel Kinzler
+ * @author Mark A. Hershberger, NicheWork, LLC
+ * @copyright © 2007, 2016 Daniel Kinzler
+ * @copyright © 2017 Mark A. Hershberger
* @license GNU General Public Licence 2.0 or later
*/
-/*
-* WARNING: you can use this extension to deny read access to some namespaces.
Keep in mind that this
-* may be circumvented in several ways. This extension doesn't try to
-* plug such holes. Also note that pages that are not readable will still be
shown in listings,
-* such as the search page, categories, etc.
-*
-* Known ways to access "hidden" pages:
-* - transcluding as template. can be avoided using $wgNonincludableNamespaces.
-* Some search messages may reveal the page existance by producing links to it
(MediaWiki:searchsubtitle,
-* MediaWiki:noexactmatch, MediaWiki:searchmenu-exists,
MediaWiki:searchmenu-new...).
-* - supplying oldid=<revisionfromhiddenpage> may work in some versions of
mediawiki. Same with diff, etc.
-*
-* NOTE: you cannot GRANT access to things forbidden by $wgGroupPermissions.
You can only DENY access
-* granted there.
-*/
+/**
+ * WARNING: you can use this extension to deny read access to some
+ * namespaces. Keep in mind that this may be circumvented in several
+ * ways. This extension doesn't try to plug such holes. Also note that
+ * pages that are not readable will still be shown in listings, such as
+ * the search page, categories, etc.
+ *
+ * Known ways to access "hidden" pages:
+ * - transcluding as template. can be avoided using $wgNonincludableNamespaces.
+ *
+ * - Some search messages may reveal the page existance by producing
+ * links to it (MediaWiki:searchsubtitle, MediaWiki:noexactmatch,
+ * MediaWiki:searchmenu-exists, MediaWiki:searchmenu-new...).
+ *
+ * - supplying oldid=<revisionfromhiddenpage> may work in some
+ * versions of mediawiki. Same with diff, etc.
+ *
+ * NOTE: you cannot GRANT access to things forbidden by
+ * $wgGroupPermissions. You can only DENY access granted there.
+ */
if ( !defined( 'MEDIAWIKI' ) ) {
- echo( "This file is an extension to the MediaWiki software and cannot
be used standalone.\n" );
+ echo( "This file is an extension to the MediaWiki software and cannot "
+ . "be used standalone.\n" );
die( 1 );
}
-$wgExtensionCredits['other'][] = array(
+$wgExtensionCredits['other'][] = [
'path' => __FILE__,
'name' => 'Lockdown',
- 'author' => array(
+ 'author' => [
'Daniel Kinzler',
+ 'Mark A. Hershberger',
'Platonides',
'...'
- ),
+ ],
'url' => 'https://mediawiki.org/wiki/Extension:Lockdown',
'descriptionmsg' => 'lockdown-desc',
'license-name' => 'GPL-2.0+'
-);
+];
$wgMessagesDirs['Lockdown'] = __DIR__ . '/i18n';
-$wgNamespacePermissionLockdown = array();
-$wgSpecialPageLockdown = array();
-$wgActionLockdown = array();
+$wgNamespacePermissionLockdown = [];
+$wgSpecialPageLockdown = [];
+$wgActionLockdown = [];
-$wgHooks['getUserPermissionsErrors'][] = 'lockdownUserPermissionsErrors';
-$wgHooks['MediaWikiPerformAction'][] = 'lockdownMediawikiPerformAction';
-$wgHooks['SearchableNamespaces'][] = 'lockdownSearchableNamespaces';
-$wgHooks['SearchGetNearMatchComplete'][] =
'lockdownSearchGetNearMatchComplete';
+$wgHooks['getUserPermissionsErrors'][] =
'Lockdown::onGetUserPermissionsErrors';
+$wgHooks['MediaWikiPerformAction'][] = 'Lockdown::onMediawikiPerformAction';
+$wgHooks['SearchableNamespaces'][] = 'Lockdown::onSearchableNamespaces';
+$wgHooks['SearchGetNearMatchComplete'][]
+ = 'Lockdown::onSearchGetNearMatchComplete';
-/**
- * @param Title $title
- * @param User $user
- * @param string $action
- * @param MessageSpecifier|array|string|bool|null $result
- * @return bool
- */
-function lockdownUserPermissionsErrors(
- Title $title,
- User $user,
- $action,
- &$result = null
-) {
- global $wgNamespacePermissionLockdown, $wgSpecialPageLockdown,
$wgWhitelistRead, $wgLang;
+class Lockdown {
- $result = null;
+ /**
+ * Fetch an appropriate permission error (or none!)
+ *
+ * @param Title $title being checked
+ * @param User $user whose access is being checked
+ * @param string $action being checked
+ * @param MessageSpecifier|array|string|bool|null &$result User
+ * permissions error to add. If none, return true. $result can be
+ * returned as a single error message key (string), or an array of
+ * error message keys when multiple messages are needed
+ * @return bool
+ * @see
https://www.mediawiki.org/wiki/Manual:Hooks/getUserPermissionsErrors
+ */
+ public static function onGetUserPermissionsErrors(
+ Title $title, User $user, $action, &$result = null
+ ) {
+ global $wgSpecialPageLockdown, $wgWhitelistRead, $wgLang;
- // don't impose extra restrictions on UI pages
- if ( $title->isCssJsSubpage() ) {
- return true;
- }
+ $result = null;
- if ( $action == 'read' && is_array( $wgWhitelistRead ) ) {
- // don't impose read restrictions on whitelisted pages
- if ( in_array( $title->getPrefixedText(), $wgWhitelistRead ) ) {
+ // don't impose extra restrictions on UI pages
+ if ( $title->isCssJsSubpage() ) {
return true;
}
- }
- $groups = null;
- $ns = $title->getNamespace();
- if ( NS_SPECIAL == $ns ) {
- foreach ( $wgSpecialPageLockdown as $page => $g ) {
- if ( !$title->isSpecial( $page ) ) continue;
- $groups = $g;
- break;
+ if ( $action == 'read' && is_array( $wgWhitelistRead ) ) {
+ // don't impose read restrictions on whitelisted pages
+ if ( in_array( $title->getPrefixedText(),
$wgWhitelistRead ) ) {
+ return true;
+ }
+ }
+
+ $groups = null;
+ $ns = $title->getNamespace();
+ if ( NS_SPECIAL == $ns ) {
+ foreach ( $wgSpecialPageLockdown as $page => $g ) {
+ if ( !$title->isSpecial( $page ) ) {
+ continue;
+ }
+ $groups = $g;
+ break;
+ }
+ } else {
+ $groups = self::namespaceGroups( $ns, $action );
+ }
+
+ if ( $groups === null ) {
+ # no restrictions
+ return true;
+ }
+
+ if ( !$groups ) {
+ # no groups allowed
+ $result = [
+ 'badaccess-group0'
+ ];
+
+ return false;
+ }
+
+ $ugroups = $user->getEffectiveGroups();
+
+ $match = array_intersect( $ugroups, $groups );
+
+ if ( $match ) {
+ # group is allowed - keep processing
+ $result = null;
+ return true;
+ } else {
+ # group is denied - abort
+ $groupLinks = array_map( [ 'User', 'makeGroupLinkWiki'
], $groups );
+
+ $result = [
+ 'badaccess-groups',
+ $wgLang->commaList( $groupLinks ),
+ count( $groups )
+ ];
+
+ return false;
}
}
- else {
- $groups = @$wgNamespacePermissionLockdown[$ns][$action];
+
+ /**
+ * See if the user is in an allowed group for this action
+ *
+ * @param OutputPage $output to use for output
+ * @param Article $article the article being acted on
+ * @param Title $title the title being acted on
+ * @param User $user who is trying this
+ * @param WebRequest $request to get any input
+ * @param MediaWiki $wiki for other info
+ * @return bool false if permission is denied
+ * @see
https://www.mediawiki.org/wiki/Manual:Hooks/MediaWikiPerformAction
+ */
+ function onMediawikiPerformAction(
+ OutputPage $output, Article $article, Title $title, User $user,
+ WebRequest $request, MediaWiki $wiki
+ ) {
+ global $wgActionLockdown, $wgLang;
+
+ $action = $wiki->getAction();
+
+ if ( !isset( $wgActionLockdown[$action] ) ) {
+ return true;
+ }
+
+ $groups = $wgActionLockdown[$action];
if ( $groups === null ) {
- $groups = @$wgNamespacePermissionLockdown['*'][$action];
+ return true;
+ }
+ if ( !$groups ) {
+ return false;
+ }
+
+ $ugroups = $user->getEffectiveGroups();
+ $match = array_intersect( $ugroups, $groups );
+
+ if ( $match ) {
+ return true;
+ } else {
+ $groupLinks = array_map( [ 'User', 'makeGroupLinkWiki'
], $groups );
+
+ $err = [
+ 'badaccess-groups', $wgLang->commaList(
$groupLinks ),
+ count( $groups )
+ ];
+ throw new PermissionsError(
+ $request->getVal( 'action' ), [ $err ]
+ );
+ }
+ }
+
+ /**
+ * Hide the namespaces that this user doesn't have permission to search
+ *
+ * @param array &$searchableNs from which namespaces will be removed
+ * @see https://www.mediawiki.org/wiki/Manual:Hooks/SearchableNamespaces
+ */
+ public static function onSearchableNamespaces( array &$searchableNs ) {
+ $user = RequestContext::getMain()->getUser();
+ $ugroups = $user->getEffectiveGroups();
+
+ foreach ( $searchableNs as $ns => $name ) {
+ if ( !self::namespaceCheck( $ns, $ugroups ) ) {
+ unset( $searchableNs[$ns] );
+ }
+ }
+ }
+
+ /**
+ * Get groups that this action is restricted to in this namespace.
+ *
+ * @param int $ns to check
+ * @param string $action to check (default: read)
+ * @return null|array of groups
+ */
+ protected static function namespaceGroups( $ns, $action = 'read' ) {
+ global $wgNamespacePermissionLockdown;
+
+ $groups = isset( $wgNamespacePermissionLockdown[$ns][$action] )
+ ? $wgNamespacePermissionLockdown[$ns][$action]
+ : null;
+ if ( $groups === null ) {
+ $groups = isset(
$wgNamespacePermissionLockdown['*'][$action] )
+ ?
$wgNamespacePermissionLockdown['*'][$action]
+ : null;
}
if ( $groups === null ) {
- $groups = @$wgNamespacePermissionLockdown[$ns]['*'];
+ $groups = isset(
$wgNamespacePermissionLockdown[$ns]['*'] )
+ ?
$wgNamespacePermissionLockdown[$ns]['*']
+ : null;
}
+ return $groups;
}
- if ( $groups === null ) {
- #no restrictions
- return true;
- }
-
- if ( !$groups ) {
- #no groups allowed
-
- $result = array(
- 'badaccess-group0'
- );
-
- return false;
- }
-
- $ugroups = $user->getEffectiveGroups();
-
- $match = array_intersect( $ugroups, $groups );
-
- if ( $match ) {
- # group is allowed - keep processing
- $result = null;
- return true;
- } else {
- # group is denied - abort
- $groupLinks = array_map( array( 'User', 'makeGroupLinkWiki' ),
$groups );
-
- $result = array(
- 'badaccess-groups',
- $wgLang->commaList( $groupLinks ),
- count( $groups )
- );
-
- return false;
- }
-}
-
-function lockdownMediawikiPerformAction (
- OutputPage $output,
- Article $article,
- Title $title,
- User $user,
- WebRequest $request,
- MediaWiki $wiki
-) {
- global $wgActionLockdown, $wgLang;
-
- $action = $wiki->getAction();
-
- if ( !isset( $wgActionLockdown[$action] ) ) {
- return true;
- }
-
- $groups = $wgActionLockdown[$action];
- if ( $groups === null ) {
- return true;
- }
- if ( !$groups ) {
- return false;
- }
-
- $ugroups = $user->getEffectiveGroups();
- $match = array_intersect( $ugroups, $groups );
-
- if ( $match ) {
- return true;
- } else {
- $groupLinks = array_map( array( 'User', 'makeGroupLinkWiki' ),
$groups );
-
- $err = array( 'badaccess-groups', $wgLang->commaList(
$groupLinks ), count( $groups ) );
- throw new PermissionsError( $request->getVal('action'), array(
$err ) );
- }
-}
-
-function lockdownSearchableNamespaces( array &$searchableNs ) {
- $user = RequestContext::getMain()->getUser();
- $ugroups = $user->getEffectiveGroups();
-
- foreach ( $searchableNs as $ns => $name ) {
- if ( !lockdownNamespace( $ns, $ugroups ) ) {
- unset( $searchableNs[$ns] );
+ /**
+ * Determine if this the user has the group to read this namespace
+ *
+ * @param int $ns to check
+ * @param array $ugroups that the user is in
+ * @return bool false if the user does not have permission
+ */
+ protected static function namespaceCheck( $ns, array $ugroups ) {
+ $groups = namespaceGroups( $ns );
+ if ( $groups && !array_intersect( $ugroups, $groups ) ) {
+ return false;
}
- }
- return true;
-}
-function lockdownNamespace( $ns, array $ugroups ) {
- global $wgNamespacePermissionLockdown;
-
- $groups = @$wgNamespacePermissionLockdown[$ns]['read'];
- if ( $groups === null ) {
- $groups = @$wgNamespacePermissionLockdown['*']['read'];
- }
- if ( $groups === null ) {
- $groups = @$wgNamespacePermissionLockdown[$ns]['*'];
+ return true;
}
- if ( $groups && !array_intersect($ugroups, $groups) ) {
- return false;
- }
+ /**
+ * Stop a "go" search for a hidden title to send you to the login
+ * required page. Will show a no such page message instead.
+ *
+ * @param string $searchterm that the user is searching
+ * @param Title $title that the user would end up on
+ * @see
https://www.mediawiki.org/wiki/Manual:Hooks/SearchGetNearMatchComplete
+ */
+ function onSearchGetNearMatchComplete( $searchterm, Title $title = null
) {
+ global $wgUser;
- return true;
-}
-
-#Stop a Go search for a hidden title to send you to the login required page.
Will show a no such page message instead.
-function lockdownSearchGetNearMatchComplete( $searchterm, Title $title = null
) {
- global $wgUser;
-
- if ( $title ) {
- $ugroups = $wgUser->getEffectiveGroups();
- if ( !lockdownNamespace( $title->getNamespace(), $ugroups ) ) {
- $title = null;
+ if ( $title ) {
+ $ugroups = $wgUser->getEffectiveGroups();
+ if ( !self::namespaceCheck( $title->getNamespace(),
$ugroups ) ) {
+ $title = null;
+ }
}
}
}
--
To view, visit https://gerrit.wikimedia.org/r/398520
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I319a09a2dad1178ea3470949e4928e9a665cc8c6
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Lockdown
Gerrit-Branch: master
Gerrit-Owner: MarkAHershberger <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits