From accf079f4df4ae664d7e0a7142ca7c988df58ce4 Mon Sep 17 00:00:00 2001
From: Brian Wolff <bawolff+wn@gmail.com>
Date: Mon, 13 Jun 2016 03:07:48 -0400
Subject: [PATCH 8/9] SECURITY: Do not allow users to undelete a page they
 can't edit or create

If the page exists, it only checks edit rights, otherwise it
checks both edit and create rights.

This would only matter on wikis that have a non-default rights
configuration where there are users with undelete rights but a
restriction level enabled that prevents them from creating/editing
pages (or they otherwise aren't allowed to edit/create)

It should be noted that the error messages aren't used in the
normal UI currently, but they could be in the future, and
extensions could potentially be using them (The backend functions
return them, but the UI functions in Special:Undelete ignore
them)

Bug: T108138
Change-Id: I164b80534cf89e0afca264e9de07431484af8508
---
 RELEASE-NOTES-1.23           |  2 ++
 includes/Title.php           | 11 +++++++++++
 includes/api/ApiUndelete.php |  8 ++++----
 languages/i18n/en.json       |  4 +++-
 languages/i18n/qqq.json      |  4 +++-
 5 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/RELEASE-NOTES-1.23 b/RELEASE-NOTES-1.23
index 372fe9e..c9ab7fd 100644
--- a/RELEASE-NOTES-1.23
+++ b/RELEASE-NOTES-1.23
@@ -24,6 +24,8 @@ This is not a release yet!
   declaration.
 * (T48143) SECURITY: Spam blacklist ineffective on encoded URLs inside file inclusion
   syntax's link parameter.
+* (T108138) SECURITY: Sysops can undelete pages, although the page is protected against
+  it.
 
 == MediaWiki 1.23.15 ==
 
diff --git a/includes/Title.php b/includes/Title.php
index 35a2883..ceef5c6 100644
--- a/includes/Title.php
+++ b/includes/Title.php
@@ -2277,6 +2277,17 @@ class Title {
 			) {
 				$errors[] = array( 'delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) );
 			}
+		} elseif ( $action === 'undelete' ) {
+			if ( count( $this->getUserPermissionsErrorsInternal( 'edit', $user, $rigor, true ) ) ) {
+				// Undeleting implies editing
+				$errors[] = [ 'undelete-cantedit' ];
+			}
+			if ( !$this->exists()
+				&& count( $this->getUserPermissionsErrorsInternal( 'create', $user, $rigor, true ) )
+			) {
+				// Undeleting where nothing currently exists implies creating
+				$errors[] = [ 'undelete-cantcreate' ];
+			}
 		}
 		return $errors;
 	}
diff --git a/includes/api/ApiUndelete.php b/includes/api/ApiUndelete.php
index 332ed51..9177470 100644
--- a/includes/api/ApiUndelete.php
+++ b/includes/api/ApiUndelete.php
@@ -32,10 +32,6 @@ class ApiUndelete extends ApiBase {
 	public function execute() {
 		$params = $this->extractRequestParams();
 
-		if ( !$this->getUser()->isAllowed( 'undelete' ) ) {
-			$this->dieUsageMsg( 'permdenied-undelete' );
-		}
-
 		if ( $this->getUser()->isBlocked() ) {
 			$this->dieUsageMsg( 'blockedtext' );
 		}
@@ -45,6 +41,10 @@ class ApiUndelete extends ApiBase {
 			$this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
 		}
 
+		if ( !$titleObj->userCan( 'undelete', $user, 'secure' ) ) {
+			$this->dieUsageMsg( 'permdenied-undelete' );
+		}
+
 		// Convert timestamps
 		if ( !isset( $params['timestamps'] ) ) {
 			$params['timestamps'] = array();
diff --git a/languages/i18n/en.json b/languages/i18n/en.json
index b6c5437..64b58c4 100644
--- a/languages/i18n/en.json
+++ b/languages/i18n/en.json
@@ -3540,5 +3540,7 @@
     "rawhtml-notallowed": "&lt;html&gt; tags cannot be used outside of normal pages.",
     "gotointerwiki": "Leaving {{SITENAME}}",
     "gotointerwiki-invalid": "The specified title was invalid.",
-    "gotointerwiki-external": "You are about to leave {{SITENAME}} to visit [[$2]] which is a separate website.\n\n[$1 Click here to continue on to $1]."
+    "gotointerwiki-external": "You are about to leave {{SITENAME}} to visit [[$2]] which is a separate website.\n\n[$1 Click here to continue on to $1].",
+    "undelete-cantedit": "You cannot undelete this page as you are not allowed to edit this page.",
+    "undelete-cantcreate": "You cannot undelete this page as there is no existing page with this name and you are not allowed to create this page."
 }
diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json
index 7198f00..61375b6 100644
--- a/languages/i18n/qqq.json
+++ b/languages/i18n/qqq.json
@@ -3704,5 +3704,7 @@ n* $1 - the action specified in the url.",
     "rawhtml-notallowed": "Error message given when $wgRawHtml = true; is set and a user uses an &lt;html&gt; tag in a system message or somewhere other than a normal page.",
     "gotointerwiki": "{{doc-special|GoToInterwiki}}\n\nSpecial:GoToInterwiki is a warning page displayed before redirecting users to external interwiki links. Its triggered by people going to something like [[Special:Search/google:foo]].",
     "gotointerwiki-invalid": "Message shown on Special:GoToInterwiki if given an invalid title.",
-    "gotointerwiki-external": "Message shown on Special:GoToInterwiki if given a external interwiki link (e.g. [[Special:GoToInterwiki/Google:Foo]]). $1 is the full url the user is trying to get to. $2 is the text of the interwiki link (e.g. \"Google:foo\")."
+    "gotointerwiki-external": "Message shown on Special:GoToInterwiki if given a external interwiki link (e.g. [[Special:GoToInterwiki/Google:Foo]]). $1 is the full url the user is trying to get to. $2 is the text of the interwiki link (e.g. \"Google:foo\").",
+    "undelete-cantedit": "Shown if the user tries to undelete a page that they cannot edit",
+    "undelete-cantcreate": "Shown if the user tries to undelete a page which currently does not exist, and they are not allowed to create it. This could for example happen on a wiki with custom protection levels where the page name has been create-protected and the user has the right to undelete but not the right to edit protected pages."
 }
-- 
2.9.3

