From fc93e722c3ebb4d26054e925a1687db34a670928 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] 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
---
 includes/Title.php           | 13 ++++++++++++-
 includes/api/ApiUndelete.php |  7 ++++---
 languages/i18n/en.json       |  4 +++-
 languages/i18n/qqq.json      |  4 +++-
 4 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/includes/Title.php b/includes/Title.php
index 589130d..550ae4a 100644
--- a/includes/Title.php
+++ b/includes/Title.php
@@ -2273,7 +2273,18 @@ class Title implements LinkTarget {
 			) {
 				$errors[] = [ '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 e24f2ce..e201c4e 100644
--- a/includes/api/ApiUndelete.php
+++ b/includes/api/ApiUndelete.php
@@ -34,9 +34,6 @@ class ApiUndelete extends ApiBase {
 
 		$params = $this->extractRequestParams();
 		$user = $this->getUser();
-		if ( !$user->isAllowed( 'undelete' ) ) {
-			$this->dieUsageMsg( 'permdenied-undelete' );
-		}
 
 		if ( $user->isBlocked() ) {
 			$this->dieBlocked( $user->getBlock() );
@@ -47,6 +44,10 @@ class ApiUndelete extends ApiBase {
 			$this->dieUsageMsg( [ 'invalidtitle', $params['title'] ] );
 		}
 
+		if ( !$titleObj->userCan( 'undelete', $user, 'secure' ) ) {
+			$this->dieUsageMsg( 'permdenied-undelete' );
+		}
+
 		// Check if user can add tags
 		if ( !is_null( $params['tags'] ) ) {
 			$ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $user );
diff --git a/languages/i18n/en.json b/languages/i18n/en.json
index 50cf789..6fb96c8 100644
--- a/languages/i18n/en.json
+++ b/languages/i18n/en.json
@@ -4169,5 +4169,7 @@
 	"linkaccounts-submit": "Link accounts",
 	"unlinkaccounts": "Unlink accounts",
 	"unlinkaccounts-success": "The account was unlinked.",
-	"authenticationdatachange-ignored": "The authentication data change was not handled. Maybe no provider was configured?"
+	"authenticationdatachange-ignored": "The authentication data change was not handled. Maybe no provider was configured?",
+	"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 9cce1fc..6627fa6 100644
--- a/languages/i18n/qqq.json
+++ b/languages/i18n/qqq.json
@@ -4347,5 +4347,7 @@
 	"linkaccounts-submit": "Text of the main submit button on [[Special:LinkAccounts]] (when there is one)",
 	"unlinkaccounts": "Title of the special page [[Special:UnlinkAccounts]] which allows the user to remove linked remote accounts.",
 	"unlinkaccounts-success": "Account unlinking form success message",
-	"authenticationdatachange-ignored": "Shown when authentication data change was unsuccessful due to configuration problems."
+	"authenticationdatachange-ignored": "Shown when authentication data change was unsuccessful due to configuration problems.",
+	"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

