CrudeProtection

From TestWiki
Jump to: navigation, search
This extension is not currently installed on this wiki.
MediaWiki logo.png
This extension is also documented at
Extension:CrudeProtection
on MediaWiki.org.

If the pages are not in sync. then this version on my test wiki is always the most up-to-date.

This extension is no longer maintained, nor supported. The extension was originally written for MW v1.6 and should work fine on that version, however other versions are untested and it is known to not work on more recent versions of MediaWiki. If someone wants to take on and extend/improve or otherwise maintain this extension then they are welcome to do so, using the same name if they choose. I have another more sophisticated page-protection extension which I currently use but which I have not yet released to the community (mainly due to time constraints). I will try and get that out sometime soon, but no promises... --HappyDog 19:09, 14 April 2010 (UTC)

About the extension[edit]

DISCLAIMER - Please make sure you fully understand what this extension does and doesn't do before using it. As the author, I am not responsible for any misconceptions you may have and the consequences they may bring!

This extension adds a very crude per-page protection mechanism to your wiki.

What the extension does[edit]

  • It allows you to specify a list of users on each page which is either:
    1. a list of users who are allowed to view the page (in which case all other users are blocked).
    2. a list of users who are denied from viewing the page (in which case all other users can view it).
  • If a user is denied then they will get an 'access denied' error when they try to view the page.
    • This includes transcluding - transcluding a protected page will protect the page that is doing the transcluding in exactly the same way.
      • However - there is a fairly simple way to avoid this and allow transclusion of a protected page!
  • The 'edit' or 'view source' tabs are removed from the interface when this happens.

What it does not do![edit]

  • Although the 'edit' tab is removed from the interface, the code does not block any actions, so by editing the URL any user can edit the page.
    • This means that they can view the source (though 'show preview' will not work).
    • This also means they can remove the protection (in which case 'show preview' will work).
  • Someone who knows how to edit the URL can therefore view both the source and the rendered page without you knowing about it.
  • They can also view the history, rollback edits, move, delete or perform any other operation through the interface without needing to modify the URL.
  • If a user tries to view an old revision of a 'protected' page they will be able to view it so long as that revision was not explicitly protected in the page source. Viewing old revisions is possible from lots of places, including the page history and recent changes.
    • Therefore to add this protection to all versions of a page, make sure you add it in the first edit and that it is never changed or removed.
  • Administrators/bureaucrats/whatever have no special powers. If they are not on the list they are blocked from viewing.
  • The title of the page is always visible - you cannot hide that the page exists, or what it is called.
  • The page will still show up in any categories that it is listed in.
  • Although you can protect image pages, you cannot stop the image itself from being included in another page.
  • Behaviour is undefined if used in the MediaWiki namespace.

In short, this extension offers a very crude protection mechanism to stop casual browsing. It is the technical equivalent of a 'keep out' sign. Please read about mw:security issues with authorization extensions

Rationale[edit]

I wrote this extension for use on my private wiki, which is used by several groups of people involved in different projects. I was uncomfortable with the fact that users could view details about projects they weren't involved in, particularly as some of them needed to be kept private. I also know all my users personally and trust them not to go snooping where they don't belong, so I created this extension as a kind of simple 'keep out' sign.

Usage[edit]

After installing the extension in the standard way, a new tag, <protect> is available to you. This flag has two optional arguments:

  1. type = "allow" or "deny" (default "allow").
    • "allow" means that only the listed users can view the page.
    • "deny" means everyone except the listed users can view the page.
  2. separator = (string)
    • Set this to the character or string that separates each user in the list.
    • The default value is a comma. This is most useful for situations where one of the usernames contains a comma.
    • You can use "\n" to use line-breaks as the separator (but not in conjunction with any other symbols, e.g. ",\n" won't work).

Examples:

 # Allow only John, Bob and Terry to view the page
 <protect>John,Bob, Terry</protect>

 # Allow everyone except "John, Jr." and "Alan" to view the page.
 # We use the pipe symbol because John, Jr. has a comma in his name.
 <protect type="deny" separator="|">John, Jr.|Alan</protect>

Whitespace is trimmed from each username, so line-breaks and other friendly layouts are allowed.

Note - only the first protect block in each page is used - all others are stripped from the rendered page, but are otherwise ignored.

Source code[edit]

Live sourcecode viewer: CrudeProtection.php
Last modified: 2024-01-27 12:32:18

<?php
if (!defined('MEDIAWIKI'))
	die("MediaWiki extensions cannot be run directly.");
/**
 * An extension to crudely protect pages from viewing by unauthorised users.
 *
 * @author Mark Clements <mclements at kennel17 dot co dot uk>
 * @copyright Copyright © 2006-2024, Mark Clements
 * @license http://creativecommons.org/licenses/by-sa/2.5/ cc-by-sa 2.5 or later
 * @version $Rev: 2439 $
 */
 
// The $wgVersion global variable was deprecated in MW 1.35, in favour of a new
// constant.  All code should use the constant rather than the variable, but for
// backwards compatibility we create the constant if it is not already defined.
// Note that the constant was back-ported to other release branches, but was not
// present in the *.0 release, so they do not affect the minimum version requirements
// for removing this shim.
// @back-compat MW < 1.35
	if (!defined("MW_VERSION"))
		define("MW_VERSION", $wgVersion);
 
// Setup version number
	$pMCExt_Version = '$Rev: 2439 $';
	$pMCExt_Version = substr($pMCExt_Version, 6, -2);
// Setup extension credits
	$wgExtensionCredits['other'][] = array(
		'name' => "CrudeProtection",
		'version' => "r" . $pMCExt_Version,
		'author' => "Mark Clements",
		'description' => "Allows users to crudely protect pages from viewing by "
						 . "unauthorised users",
		'url' => "http://www.mediawiki.org/wiki/Extension:CrudeProtection",
	);
// Tidy up
	unset($pMCExt_Version);
 
	$pCrudeProtection_Messages = array(
		'crudeprotection_title' => "Access denied",
		'crudeprotection_text' 	=> "You do not have permission to view this page.",
	);
 
	$wgExtensionFunctions[] = "wfCrudeProtection";
 
	function wfCrudeProtection() {
		global $wgMessageCache, $wgParser, $wgHooks;
		global $pCrudeProtection_Messages;
 
	// Later MediaWiki versions require a separate i18n file, which is annoying.
	// As this is only used on the error page, I have just disabled it for now.
	// Requires wiki to manually set these values, otherwise they will get crappy
	// output.
	// TODO: Resolve this properly.
		if (is_object($wgMessageCache)) {
			$wgMessageCache->addMessages($pCrudeProtection_Messages);
		}
 
	// Parser hooks
		$wgHooks['SkinTemplateContentActions'][] = "wfCrudeProtection_RemoveEditTab";
		$wgHooks['OutputPageBeforeHTML'][] = "wfCrudeProtection_DoBlock";
 
	// If this is MediaWiki < 1.12, then the ParserFirstCallInit hook does not exist,
	// therefore we manually call our hook registration function with the global
	// Parser object.
	// @back-compat MW < 1.12
		if (version_compare(MW_VERSION, '1.12', '<')) {
			wfCrudeProtection_RegisterParserHooks($wgParser);
		}
	}
 
// Parser hooks.
// This hook was added in MediaWiki 1.12.  For older versions, of MediaWiki, we
// manually call the hook function as part of the main extension registration
// function, instead.
	$wgHooks['ParserFirstCallInit'][] = "wfCrudeProtection_RegisterParserHooks";
 
	function wfCrudeProtection_RegisterParserHooks(&$Parser) {
	// Specific tags to be parsed
		$Parser->setHook( "protect", "wfCrudeProtection_Protect" );
 
		return true;
	}
 
	function wfCrudeProtection_Protect($Input, $Args, $Parser = null) {
		global $wgOut, $wgUser, $wgParser;
		global $pBlocked;
 
	// The $Parser argument was added in MediaWiki 1.5.8.  Therefore, to keep
	// compatibility with older versions, we need to default the function argument
	// to null and default to the global $wgParser argument if it is not set.
	// @back-compat MW < 1.5.8
		if (!isset($Parser))
			$Parser = $wgParser;
 
	// We need to disable caching for any page that contains a <protect> tag.
		wfCrudeProtection_DisableCache($Parser);
 
	// Only respond to the first <protect> block.  Ignore all others.
		if (!isset($pBlocked)) {
			if (isset($Args['type'])) {
				$Type = strtolower($Args['type']);
				if ($Type != "allow" && $Type != "deny")
					$Type = "allow";
			}
			else
				$Type = "allow";
 
		// Allow "\n" to be specified as a line-break character.
			if (isset($Args['separator'])) {
				$Separator = $Args['separator'];
				if ($Separator == "\\n")
					$Separator = "\n";
			}
			else
				$Separator = ",";
 
		// Set appropriate default value, for if the user is not in the list of
		// users.
			if ($Type == "allow")
				$pBlocked = true;
			elseif ($Type == "deny")
				$pBlocked = false;
 
		// Check if the user is in the list - if so, then swap their status.
			$Users = explode($Separator, $Input);
			foreach ($Users as $Key => $Value) {
				$Value = trim($Value);
				if ($wgUser->getName() == $Value && $Value != "") {
					$pBlocked = !$pBlocked;
					break;
				}
			}
 
		// If they are blocked, they will be redirected to error page, via
		// the OutputPageBeforeHTML hook.
		}
		return "";
	}
 
	function wfCrudeProtection_DoBlock(&$out, &$text) {
		global $pBlocked;
 
		if ($pBlocked) {
			throw new ErrorPageError('crudeprotection_title',
									 'crudeprotection_text');
			return false;
		}
 
		return true;
	}
 
	function wfCrudeProtection_RemoveEditTab(&$ContentActions) {
		global $pBlocked;
 
		if ($pBlocked) {
			unset($ContentActions['edit']);
			unset($ContentActions['viewsource']);
		}
 
		return true;
	}
 
// wfCrudeProtection_DisableCache()
// Prevents the results of the current parse from being cached.  This makes most
// sense in the context of parsing a full page, but may make sense in other parsing
// contexts, too.
// Primarily provided for backwards-compatibility reasons, but may still be useful
// when older MW versions no longer need to be supported, for clarity and brevity.
	function wfCrudeProtection_DisableCache($objParser) {
	// Prior to MW 1.28, you simply called disableCache() on the Parser instance in
	// order to disable the cache.  In MW 1.28 this was deprecated and it was
	// ultimately removed in MW 1.35.
	// Note that we need a version check here as this can't be feature-detected.  All
	// relevant functions have existed since at least MW 1.17 and we don't want to
	// call disableCache() after deprecation, as it will emit notices.
	// TODO: Although the deprecation was made in MW 1.28, it is possible that the
	//		 new technique worked correctly in older MW versions.  It may therefore
	//		 be possible to turn this into a feature-detection check after all.
	// @back-compat MW < 1.28
		if (version_compare(MW_VERSION, "<", "1.28")) {
			$objParser->disableCache();
		}
	// In more recent MediaWiki versions, you need to first retrieve the ParserOutput
	// object from the Parser and then set the cache expiry to zero seconds.
	// TODO: Although the deprecation was made in MW 1.28, it is possible that the
	//		 new technique worked correctly in older MW versions.  It may therefore
	//		 be possible to turn this into a feature-detection check after all.
		else {
			$objParserOutput = $objParser->getOutput();
			$objParserOutput->updateCacheExpiry(0);
		}
	}