Version Description
Download this release
Release Info
Developer | dmchale |
Plugin | Disable REST API |
Version | v1.5 |
Comparing to | |
See all releases |
Code changes from version 1.4.3 to v1.5
- admin.php +95 -95
- classes/disable-rest-api.php +218 -218
- classes/requirements-check.php +74 -0
- disable-json-api.php +32 -15
- functions/legacy.php +16 -16
- readme.txt +20 -9
admin.php
CHANGED
@@ -1,95 +1,95 @@
|
|
1 |
-
<style>
|
2 |
-
#DRA_container ul li {
|
3 |
-
padding-left: 20px;
|
4 |
-
}
|
5 |
-
|
6 |
-
#DRA_container em {
|
7 |
-
font-size: 0.8em;
|
8 |
-
}
|
9 |
-
</style>
|
10 |
-
|
11 |
-
<script>
|
12 |
-
function dra_namespace_click(namespace, id) {
|
13 |
-
if (jQuery('#dra_namespace_' + id).is(":checked")) {
|
14 |
-
jQuery("input[data-namespace='" + namespace + "']").prop('checked', true);
|
15 |
-
} else {
|
16 |
-
jQuery("input[data-namespace='" + namespace + "']").prop('checked', false);
|
17 |
-
}
|
18 |
-
};
|
19 |
-
</script>
|
20 |
-
|
21 |
-
<div class="wrap">
|
22 |
-
<h1><?php echo esc_html__( "Disable REST API", "disable-json-api" ); ?></h1>
|
23 |
-
<?php settings_errors( 'DRA-notices' ); ?>
|
24 |
-
<p><?php echo esc_html__( "By default, this plugin ensures that the entire REST API is protected from non-authenticated users. You may use this page to specify which endpoints should be allowed to behave as normal.", "disable-json-api" ); ?></p>
|
25 |
-
<p>
|
26 |
-
<strong><?php echo esc_html__( "IMPORTANT NOTE:", "disable-json-api" ); ?></strong> <?php echo esc_html__( "Checking a box merely restores default functionality to an endpoint
|
27 |
-
</p>
|
28 |
-
|
29 |
-
<form method="post" action="" id="DRA_form">
|
30 |
-
<?php wp_nonce_field( 'DRA_admin_nonce' ); ?>
|
31 |
-
|
32 |
-
<div id="DRA_container"><?php DRA_display_route_checkboxes(); ?></div>
|
33 |
-
|
34 |
-
<?php submit_button(); ?>
|
35 |
-
<input type="submit" name="reset"
|
36 |
-
value="<?php echo esc_attr__( "Reset Whitelisted Routes", "disable-json-api" ); ?>"
|
37 |
-
onclick="return confirm('<?php echo esc_attr__( "Are you sure you wish to clear all whitelisted
|
38 |
-
</form>
|
39 |
-
</div>
|
40 |
-
|
41 |
-
<?php
|
42 |
-
/**
|
43 |
-
* Loop through all routes returned by the REST API and display them on-screen
|
44 |
-
*
|
45 |
-
*/
|
46 |
-
function DRA_display_route_checkboxes() {
|
47 |
-
$wp_rest_server = rest_get_server();
|
48 |
-
$all_namespaces = $wp_rest_server->get_namespaces();
|
49 |
-
$all_routes = array_keys( $wp_rest_server->get_routes() );
|
50 |
-
$whitelisted_routes = is_array( get_option( 'DRA_route_whitelist' ) ) ? get_option( 'DRA_route_whitelist' ) : array();
|
51 |
-
|
52 |
-
$loopCounter = 0;
|
53 |
-
$current_namespace = '';
|
54 |
-
|
55 |
-
foreach ( $all_routes as $route ) {
|
56 |
-
$is_route_namespace = in_array( ltrim( $route, "/" ), $all_namespaces );
|
57 |
-
$checkedProp = DRA_get_route_checked_prop( $route, $whitelisted_routes );
|
58 |
-
|
59 |
-
if ( $is_route_namespace || "/" == $route ) {
|
60 |
-
$current_namespace = $route;
|
61 |
-
if ( 0 != $loopCounter ) {
|
62 |
-
echo "</ul>";
|
63 |
-
}
|
64 |
-
|
65 |
-
$route_for_display = ( "/" == $route ) ? "/ <em>" . esc_html__( "REST API ROOT", "disable-json-api" ) . "</em>" : esc_html( $route );
|
66 |
-
echo "<h2><label><input name='rest_routes[]' value='$route' type='checkbox' id='dra_namespace_$loopCounter' onclick='dra_namespace_click(\"$route\", $loopCounter)' $checkedProp> $route_for_display</label></h2><ul>";
|
67 |
-
|
68 |
-
if ( "/" == $route ) {
|
69 |
-
echo "<li>" . sprintf( esc_html__( "On this website, the REST API root is %s", "disable-json-api" ), "<strong>" . rest_url() . "</strong>" ) . "</li>";
|
70 |
-
}
|
71 |
-
|
72 |
-
} else {
|
73 |
-
echo "<li><label><input name='rest_routes[]' value='$route' type='checkbox' data-namespace='$current_namespace' $checkedProp> " . esc_html( $route ) . "</label></li>";
|
74 |
-
}
|
75 |
-
|
76 |
-
$loopCounter ++;
|
77 |
-
}
|
78 |
-
echo "</ul>";
|
79 |
-
}
|
80 |
-
|
81 |
-
|
82 |
-
/**
|
83 |
-
* During comparison, encode the route being requested in the same fashion that it's stored in the database option
|
84 |
-
* Encoding during save happens in Disable_REST_API::maybe_process_settings_form()
|
85 |
-
*
|
86 |
-
* @param $route
|
87 |
-
* @param $whitelisted_routes
|
88 |
-
*
|
89 |
-
* @return string
|
90 |
-
*/
|
91 |
-
function DRA_get_route_checked_prop( $route, $whitelisted_routes ) {
|
92 |
-
$is_route_checked = in_array( esc_html( $route ), $whitelisted_routes, true );
|
93 |
-
|
94 |
-
return checked( $is_route_checked, true, false );
|
95 |
-
}
|
1 |
+
<style>
|
2 |
+
#DRA_container ul li {
|
3 |
+
padding-left: 20px;
|
4 |
+
}
|
5 |
+
|
6 |
+
#DRA_container em {
|
7 |
+
font-size: 0.8em;
|
8 |
+
}
|
9 |
+
</style>
|
10 |
+
|
11 |
+
<script>
|
12 |
+
function dra_namespace_click(namespace, id) {
|
13 |
+
if (jQuery('#dra_namespace_' + id).is(":checked")) {
|
14 |
+
jQuery("input[data-namespace='" + namespace + "']").prop('checked', true);
|
15 |
+
} else {
|
16 |
+
jQuery("input[data-namespace='" + namespace + "']").prop('checked', false);
|
17 |
+
}
|
18 |
+
};
|
19 |
+
</script>
|
20 |
+
|
21 |
+
<div class="wrap">
|
22 |
+
<h1><?php echo esc_html__( "Disable REST API", "disable-json-api" ); ?></h1>
|
23 |
+
<?php settings_errors( 'DRA-notices' ); ?>
|
24 |
+
<p><?php echo esc_html__( "By default, this plugin ensures that the entire REST API is protected from non-authenticated users. You may use this page to specify which endpoints should be allowed to behave as normal.", "disable-json-api" ); ?></p>
|
25 |
+
<p>
|
26 |
+
<strong><?php echo esc_html__( "IMPORTANT NOTE:", "disable-json-api" ); ?></strong> <?php echo esc_html__( "Checking a box merely restores default functionality to an endpoint. Other authentication and/or permissions may still be required for access, or other themes/plugins may also affect access to those endpoints.", "disable-json-api" ); ?>
|
27 |
+
</p>
|
28 |
+
|
29 |
+
<form method="post" action="" id="DRA_form">
|
30 |
+
<?php wp_nonce_field( 'DRA_admin_nonce' ); ?>
|
31 |
+
|
32 |
+
<div id="DRA_container"><?php DRA_display_route_checkboxes(); ?></div>
|
33 |
+
|
34 |
+
<?php submit_button(); ?>
|
35 |
+
<input type="submit" name="reset"
|
36 |
+
value="<?php echo esc_attr__( "Reset Whitelisted Routes", "disable-json-api" ); ?>"
|
37 |
+
onclick="return confirm('<?php echo esc_attr__( "Are you sure you wish to clear all whitelisted routes?", "disable-json-api" ); ?>');">
|
38 |
+
</form>
|
39 |
+
</div>
|
40 |
+
|
41 |
+
<?php
|
42 |
+
/**
|
43 |
+
* Loop through all routes returned by the REST API and display them on-screen
|
44 |
+
*
|
45 |
+
*/
|
46 |
+
function DRA_display_route_checkboxes() {
|
47 |
+
$wp_rest_server = rest_get_server();
|
48 |
+
$all_namespaces = $wp_rest_server->get_namespaces();
|
49 |
+
$all_routes = array_keys( $wp_rest_server->get_routes() );
|
50 |
+
$whitelisted_routes = is_array( get_option( 'DRA_route_whitelist' ) ) ? get_option( 'DRA_route_whitelist' ) : array();
|
51 |
+
|
52 |
+
$loopCounter = 0;
|
53 |
+
$current_namespace = '';
|
54 |
+
|
55 |
+
foreach ( $all_routes as $route ) {
|
56 |
+
$is_route_namespace = in_array( ltrim( $route, "/" ), $all_namespaces );
|
57 |
+
$checkedProp = DRA_get_route_checked_prop( $route, $whitelisted_routes );
|
58 |
+
|
59 |
+
if ( $is_route_namespace || "/" == $route ) {
|
60 |
+
$current_namespace = $route;
|
61 |
+
if ( 0 != $loopCounter ) {
|
62 |
+
echo "</ul>";
|
63 |
+
}
|
64 |
+
|
65 |
+
$route_for_display = ( "/" == $route ) ? "/ <em>" . esc_html__( "REST API ROOT", "disable-json-api" ) . "</em>" : esc_html( $route );
|
66 |
+
echo "<h2><label><input name='rest_routes[]' value='$route' type='checkbox' id='dra_namespace_$loopCounter' onclick='dra_namespace_click(\"$route\", $loopCounter)' $checkedProp> $route_for_display</label></h2><ul>";
|
67 |
+
|
68 |
+
if ( "/" == $route ) {
|
69 |
+
echo "<li>" . sprintf( esc_html__( "On this website, the REST API root is %s", "disable-json-api" ), "<strong>" . rest_url() . "</strong>" ) . "</li>";
|
70 |
+
}
|
71 |
+
|
72 |
+
} else {
|
73 |
+
echo "<li><label><input name='rest_routes[]' value='$route' type='checkbox' data-namespace='$current_namespace' $checkedProp> " . esc_html( $route ) . "</label></li>";
|
74 |
+
}
|
75 |
+
|
76 |
+
$loopCounter ++;
|
77 |
+
}
|
78 |
+
echo "</ul>";
|
79 |
+
}
|
80 |
+
|
81 |
+
|
82 |
+
/**
|
83 |
+
* During comparison, encode the route being requested in the same fashion that it's stored in the database option
|
84 |
+
* Encoding during save happens in Disable_REST_API::maybe_process_settings_form()
|
85 |
+
*
|
86 |
+
* @param $route
|
87 |
+
* @param $whitelisted_routes
|
88 |
+
*
|
89 |
+
* @return string
|
90 |
+
*/
|
91 |
+
function DRA_get_route_checked_prop( $route, $whitelisted_routes ) {
|
92 |
+
$is_route_checked = in_array( esc_html( $route ), $whitelisted_routes, true );
|
93 |
+
|
94 |
+
return checked( $is_route_checked, true, false );
|
95 |
+
}
|
classes/disable-rest-api.php
CHANGED
@@ -1,218 +1,218 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Disable_REST_API class
|
5 |
-
*
|
6 |
-
* Most of the work is done in here
|
7 |
-
*/
|
8 |
-
class Disable_REST_API {
|
9 |
-
|
10 |
-
const MENU_SLUG = 'disable_rest_api_settings';
|
11 |
-
const CAPABILITY = 'manage_options';
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Stores 'disable-json-api/disable-json-api.php' typically
|
15 |
-
*
|
16 |
-
* @var string
|
17 |
-
*/
|
18 |
-
private $base_file_path;
|
19 |
-
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Disable_REST_API constructor.
|
23 |
-
*
|
24 |
-
* @param $path
|
25 |
-
*/
|
26 |
-
public function __construct( $path ) {
|
27 |
-
|
28 |
-
// Set variable so the class knows how to reference the plugin
|
29 |
-
$this->base_file_path = plugin_basename( $path );
|
30 |
-
|
31 |
-
add_action( 'admin_menu', array( &$this, 'define_admin_link' ) );
|
32 |
-
|
33 |
-
add_filter( 'rest_authentication_errors', array( &$this, 'whitelist_routes' ), 20 );
|
34 |
-
|
35 |
-
}
|
36 |
-
|
37 |
-
|
38 |
-
/**
|
39 |
-
* Checks for a current route being requested, and processes the whitelist
|
40 |
-
*
|
41 |
-
* @param $access
|
42 |
-
*
|
43 |
-
* @return WP_Error|null|boolean
|
44 |
-
*/
|
45 |
-
public function whitelist_routes( $access ) {
|
46 |
-
|
47 |
-
// Return current value of $access and skip all plugin functionality
|
48 |
-
if ( $this->allow_rest_api() ) {
|
49 |
-
return $access;
|
50 |
-
}
|
51 |
-
|
52 |
-
$current_route = $this->get_current_route();
|
53 |
-
|
54 |
-
if ( !
|
55 |
-
return $this->get_wp_error( $access );
|
56 |
-
}
|
57 |
-
|
58 |
-
return $access;
|
59 |
-
|
60 |
-
}
|
61 |
-
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Current REST route getter.
|
65 |
-
*
|
66 |
-
* @return string
|
67 |
-
*/
|
68 |
-
private function get_current_route() {
|
69 |
-
$rest_route = $GLOBALS['wp']->query_vars['rest_route'];
|
70 |
-
|
71 |
-
return ( empty( $rest_route ) || '/' == $rest_route ) ?
|
72 |
-
$rest_route :
|
73 |
-
untrailingslashit( $rest_route );
|
74 |
-
}
|
75 |
-
|
76 |
-
|
77 |
-
/**
|
78 |
-
* Checks a route for whether it belongs to the whitelist
|
79 |
-
*
|
80 |
-
* @param $currentRoute
|
81 |
-
*
|
82 |
-
* @return boolean
|
83 |
-
*/
|
84 |
-
private function is_whitelisted( $currentRoute ) {
|
85 |
-
|
86 |
-
return array_reduce( $this->get_route_whitelist_option(), function ( $isMatched, $pattern ) use ( $currentRoute ) {
|
87 |
-
return $isMatched || (bool) preg_match( '@^' . htmlspecialchars_decode( $pattern ) . '$@i', $currentRoute );
|
88 |
-
}, false );
|
89 |
-
|
90 |
-
}
|
91 |
-
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Get `DRA_route_whitelist` option array from database
|
95 |
-
*
|
96 |
-
* @return array
|
97 |
-
*/
|
98 |
-
private function get_route_whitelist_option() {
|
99 |
-
|
100 |
-
return (array) get_option( 'DRA_route_whitelist', array() );
|
101 |
-
|
102 |
-
}
|
103 |
-
|
104 |
-
|
105 |
-
/**
|
106 |
-
* Add a menu
|
107 |
-
*
|
108 |
-
* @return void
|
109 |
-
*/
|
110 |
-
public function define_admin_link() {
|
111 |
-
|
112 |
-
add_options_page( esc_html__( 'Disable REST API Settings', 'disable-json-api' ), esc_html__( 'Disable REST API', 'disable-json-api' ), self::CAPABILITY, self::MENU_SLUG, array(
|
113 |
-
&$this,
|
114 |
-
'settings_page'
|
115 |
-
) );
|
116 |
-
add_filter( "plugin_action_links_$this->base_file_path", array( &$this, 'settings_link' ) );
|
117 |
-
|
118 |
-
}
|
119 |
-
|
120 |
-
|
121 |
-
/**
|
122 |
-
* Add Settings Link to plugins page
|
123 |
-
*
|
124 |
-
* @param $links
|
125 |
-
*
|
126 |
-
* @return array
|
127 |
-
*/
|
128 |
-
public function settings_link( $links ) {
|
129 |
-
|
130 |
-
$settings_url = menu_page_url( self::MENU_SLUG, false );
|
131 |
-
$settings_link = "<a href='$settings_url'>" . esc_html__( "Settings", "disable-json-api" ) . "</a>";
|
132 |
-
array_unshift( $links, $settings_link );
|
133 |
-
|
134 |
-
return $links;
|
135 |
-
}
|
136 |
-
|
137 |
-
|
138 |
-
/**
|
139 |
-
* Menu Callback
|
140 |
-
*
|
141 |
-
* @return void
|
142 |
-
*/
|
143 |
-
public function settings_page() {
|
144 |
-
|
145 |
-
$this->maybe_process_settings_form();
|
146 |
-
|
147 |
-
// Render the settings template
|
148 |
-
include( __DIR__ . "/../admin.php" );
|
149 |
-
|
150 |
-
}
|
151 |
-
|
152 |
-
|
153 |
-
/**
|
154 |
-
* Process the admin page settings form submission
|
155 |
-
*
|
156 |
-
* @return void
|
157 |
-
*/
|
158 |
-
private function maybe_process_settings_form() {
|
159 |
-
|
160 |
-
if ( ! ( isset( $_POST['_wpnonce'] ) && check_admin_referer( 'DRA_admin_nonce' ) ) ) {
|
161 |
-
return;
|
162 |
-
}
|
163 |
-
|
164 |
-
if ( ! current_user_can( self::CAPABILITY ) ) {
|
165 |
-
return;
|
166 |
-
}
|
167 |
-
|
168 |
-
// Catch the routes that should be whitelisted
|
169 |
-
$rest_routes = ( isset( $_POST['rest_routes'] ) ) ?
|
170 |
-
array_map( 'esc_html', wp_unslash( $_POST['rest_routes'] ) ) :
|
171 |
-
null;
|
172 |
-
|
173 |
-
// If resetting or whitelist is empty, clear the option and exit the function
|
174 |
-
if ( empty( $rest_routes ) || isset( $_POST['reset'] ) ) {
|
175 |
-
delete_option( 'DRA_route_whitelist' );
|
176 |
-
add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), esc_html__( 'All whitelists have been removed.' ), 'updated' );
|
177 |
-
|
178 |
-
return;
|
179 |
-
}
|
180 |
-
|
181 |
-
// Save whitelist to the Options table
|
182 |
-
update_option( 'DRA_route_whitelist', $rest_routes );
|
183 |
-
add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), esc_html__( 'Whitelist settings saved.' ), 'updated' );
|
184 |
-
|
185 |
-
}
|
186 |
-
|
187 |
-
|
188 |
-
/**
|
189 |
-
* Allow carte blanche access for logged-in users (or allow override via filter)
|
190 |
-
*
|
191 |
-
* @return bool
|
192 |
-
*/
|
193 |
-
private function allow_rest_api() {
|
194 |
-
return (bool) apply_filters( 'dra_allow_rest_api', is_user_logged_in() );
|
195 |
-
}
|
196 |
-
|
197 |
-
|
198 |
-
/**
|
199 |
-
* If $access is already a WP_Error object, add our error to the list
|
200 |
-
* Otherwise return a new one
|
201 |
-
*
|
202 |
-
* @param $access
|
203 |
-
*
|
204 |
-
* @return WP_Error
|
205 |
-
*/
|
206 |
-
private function get_wp_error( $access ) {
|
207 |
-
$error_message = esc_html__( 'DRA: Only authenticated users can access the REST API.', 'disable-json-api' );
|
208 |
-
|
209 |
-
if ( is_wp_error( $access ) ) {
|
210 |
-
$access->add( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) );
|
211 |
-
|
212 |
-
return $access;
|
213 |
-
}
|
214 |
-
|
215 |
-
return new WP_Error( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) );
|
216 |
-
}
|
217 |
-
|
218 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Disable_REST_API class
|
5 |
+
*
|
6 |
+
* Most of the work is done in here
|
7 |
+
*/
|
8 |
+
class Disable_REST_API {
|
9 |
+
|
10 |
+
const MENU_SLUG = 'disable_rest_api_settings';
|
11 |
+
const CAPABILITY = 'manage_options';
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Stores 'disable-json-api/disable-json-api.php' typically
|
15 |
+
*
|
16 |
+
* @var string
|
17 |
+
*/
|
18 |
+
private $base_file_path;
|
19 |
+
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Disable_REST_API constructor.
|
23 |
+
*
|
24 |
+
* @param $path
|
25 |
+
*/
|
26 |
+
public function __construct( $path ) {
|
27 |
+
|
28 |
+
// Set variable so the class knows how to reference the plugin
|
29 |
+
$this->base_file_path = plugin_basename( $path );
|
30 |
+
|
31 |
+
add_action( 'admin_menu', array( &$this, 'define_admin_link' ) );
|
32 |
+
|
33 |
+
add_filter( 'rest_authentication_errors', array( &$this, 'whitelist_routes' ), 20 );
|
34 |
+
|
35 |
+
}
|
36 |
+
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Checks for a current route being requested, and processes the whitelist
|
40 |
+
*
|
41 |
+
* @param $access
|
42 |
+
*
|
43 |
+
* @return WP_Error|null|boolean
|
44 |
+
*/
|
45 |
+
public function whitelist_routes( $access ) {
|
46 |
+
|
47 |
+
// Return current value of $access and skip all plugin functionality
|
48 |
+
if ( $this->allow_rest_api() ) {
|
49 |
+
return $access;
|
50 |
+
}
|
51 |
+
|
52 |
+
$current_route = $this->get_current_route();
|
53 |
+
|
54 |
+
if ( ! $this->is_whitelisted( $current_route ) ) {
|
55 |
+
return $this->get_wp_error( $access );
|
56 |
+
}
|
57 |
+
|
58 |
+
return $access;
|
59 |
+
|
60 |
+
}
|
61 |
+
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Current REST route getter.
|
65 |
+
*
|
66 |
+
* @return string
|
67 |
+
*/
|
68 |
+
private function get_current_route() {
|
69 |
+
$rest_route = $GLOBALS['wp']->query_vars['rest_route'];
|
70 |
+
|
71 |
+
return ( empty( $rest_route ) || '/' == $rest_route ) ?
|
72 |
+
$rest_route :
|
73 |
+
untrailingslashit( $rest_route );
|
74 |
+
}
|
75 |
+
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Checks a route for whether it belongs to the whitelist
|
79 |
+
*
|
80 |
+
* @param $currentRoute
|
81 |
+
*
|
82 |
+
* @return boolean
|
83 |
+
*/
|
84 |
+
private function is_whitelisted( $currentRoute ) {
|
85 |
+
|
86 |
+
return array_reduce( $this->get_route_whitelist_option(), function ( $isMatched, $pattern ) use ( $currentRoute ) {
|
87 |
+
return $isMatched || (bool) preg_match( '@^' . htmlspecialchars_decode( $pattern ) . '$@i', $currentRoute );
|
88 |
+
}, false );
|
89 |
+
|
90 |
+
}
|
91 |
+
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Get `DRA_route_whitelist` option array from database
|
95 |
+
*
|
96 |
+
* @return array
|
97 |
+
*/
|
98 |
+
private function get_route_whitelist_option() {
|
99 |
+
|
100 |
+
return (array) get_option( 'DRA_route_whitelist', array() );
|
101 |
+
|
102 |
+
}
|
103 |
+
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Add a menu
|
107 |
+
*
|
108 |
+
* @return void
|
109 |
+
*/
|
110 |
+
public function define_admin_link() {
|
111 |
+
|
112 |
+
add_options_page( esc_html__( 'Disable REST API Settings', 'disable-json-api' ), esc_html__( 'Disable REST API', 'disable-json-api' ), self::CAPABILITY, self::MENU_SLUG, array(
|
113 |
+
&$this,
|
114 |
+
'settings_page'
|
115 |
+
) );
|
116 |
+
add_filter( "plugin_action_links_$this->base_file_path", array( &$this, 'settings_link' ) );
|
117 |
+
|
118 |
+
}
|
119 |
+
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Add Settings Link to plugins page
|
123 |
+
*
|
124 |
+
* @param $links
|
125 |
+
*
|
126 |
+
* @return array
|
127 |
+
*/
|
128 |
+
public function settings_link( $links ) {
|
129 |
+
|
130 |
+
$settings_url = menu_page_url( self::MENU_SLUG, false );
|
131 |
+
$settings_link = "<a href='$settings_url'>" . esc_html__( "Settings", "disable-json-api" ) . "</a>";
|
132 |
+
array_unshift( $links, $settings_link );
|
133 |
+
|
134 |
+
return $links;
|
135 |
+
}
|
136 |
+
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Menu Callback
|
140 |
+
*
|
141 |
+
* @return void
|
142 |
+
*/
|
143 |
+
public function settings_page() {
|
144 |
+
|
145 |
+
$this->maybe_process_settings_form();
|
146 |
+
|
147 |
+
// Render the settings template
|
148 |
+
include( __DIR__ . "/../admin.php" );
|
149 |
+
|
150 |
+
}
|
151 |
+
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Process the admin page settings form submission
|
155 |
+
*
|
156 |
+
* @return void
|
157 |
+
*/
|
158 |
+
private function maybe_process_settings_form() {
|
159 |
+
|
160 |
+
if ( ! ( isset( $_POST['_wpnonce'] ) && check_admin_referer( 'DRA_admin_nonce' ) ) ) {
|
161 |
+
return;
|
162 |
+
}
|
163 |
+
|
164 |
+
if ( ! current_user_can( self::CAPABILITY ) ) {
|
165 |
+
return;
|
166 |
+
}
|
167 |
+
|
168 |
+
// Catch the routes that should be whitelisted
|
169 |
+
$rest_routes = ( isset( $_POST['rest_routes'] ) ) ?
|
170 |
+
array_map( 'esc_html', wp_unslash( $_POST['rest_routes'] ) ) :
|
171 |
+
null;
|
172 |
+
|
173 |
+
// If resetting or whitelist is empty, clear the option and exit the function
|
174 |
+
if ( empty( $rest_routes ) || isset( $_POST['reset'] ) ) {
|
175 |
+
delete_option( 'DRA_route_whitelist' );
|
176 |
+
add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), esc_html__( 'All whitelists have been removed.', 'disable-json-api' ), 'updated' );
|
177 |
+
|
178 |
+
return;
|
179 |
+
}
|
180 |
+
|
181 |
+
// Save whitelist to the Options table
|
182 |
+
update_option( 'DRA_route_whitelist', $rest_routes );
|
183 |
+
add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), esc_html__( 'Whitelist settings saved.', 'disable-json-api' ), 'updated' );
|
184 |
+
|
185 |
+
}
|
186 |
+
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Allow carte blanche access for logged-in users (or allow override via filter)
|
190 |
+
*
|
191 |
+
* @return bool
|
192 |
+
*/
|
193 |
+
private function allow_rest_api() {
|
194 |
+
return (bool) apply_filters( 'dra_allow_rest_api', is_user_logged_in() );
|
195 |
+
}
|
196 |
+
|
197 |
+
|
198 |
+
/**
|
199 |
+
* If $access is already a WP_Error object, add our error to the list
|
200 |
+
* Otherwise return a new one
|
201 |
+
*
|
202 |
+
* @param $access
|
203 |
+
*
|
204 |
+
* @return WP_Error
|
205 |
+
*/
|
206 |
+
private function get_wp_error( $access ) {
|
207 |
+
$error_message = esc_html__( 'DRA: Only authenticated users can access the REST API.', 'disable-json-api' );
|
208 |
+
|
209 |
+
if ( is_wp_error( $access ) ) {
|
210 |
+
$access->add( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) );
|
211 |
+
|
212 |
+
return $access;
|
213 |
+
}
|
214 |
+
|
215 |
+
return new WP_Error( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) );
|
216 |
+
}
|
217 |
+
|
218 |
+
}
|
classes/requirements-check.php
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Disable_REST_API_Requirements_Check
|
4 |
+
*
|
5 |
+
* Taken from https://markjaquith.wordpress.com/2018/02/19/handling-old-wordpress-and-php-versions-in-your-plugin/
|
6 |
+
*
|
7 |
+
*/
|
8 |
+
|
9 |
+
class Disable_REST_API_Requirements_Check {
|
10 |
+
private $title = '';
|
11 |
+
private $php = '5.2.4';
|
12 |
+
private $wp = '3.8';
|
13 |
+
private $file;
|
14 |
+
|
15 |
+
public function __construct( $args ) {
|
16 |
+
foreach ( array( 'title', 'php', 'wp', 'file' ) as $setting ) {
|
17 |
+
if ( isset( $args[$setting] ) ) {
|
18 |
+
$this->$setting = $args[$setting];
|
19 |
+
}
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
public function passes() {
|
24 |
+
$passes = $this->php_passes() && $this->wp_passes();
|
25 |
+
if ( ! $passes ) {
|
26 |
+
add_action( 'admin_notices', array( $this, 'deactivate' ) );
|
27 |
+
}
|
28 |
+
return $passes;
|
29 |
+
}
|
30 |
+
|
31 |
+
public function deactivate() {
|
32 |
+
if ( isset( $this->file ) ) {
|
33 |
+
deactivate_plugins( plugin_basename( $this->file ) );
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
private function php_passes() {
|
38 |
+
if ( $this->__php_at_least( $this->php ) ) {
|
39 |
+
return true;
|
40 |
+
} else {
|
41 |
+
add_action( 'admin_notices', array( $this, 'php_version_notice' ) );
|
42 |
+
return false;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
|
46 |
+
private static function __php_at_least( $min_version ) {
|
47 |
+
return version_compare( phpversion(), $min_version, '>=' );
|
48 |
+
}
|
49 |
+
|
50 |
+
public function php_version_notice() {
|
51 |
+
echo '<div class="error">';
|
52 |
+
echo "<p>The “" . esc_html( $this->title ) . "” plugin cannot run on PHP versions older than " . $this->php . '. Please contact your host and ask them to upgrade.</p>';
|
53 |
+
echo '</div>';
|
54 |
+
}
|
55 |
+
|
56 |
+
private function wp_passes() {
|
57 |
+
if ( $this->__wp_at_least( $this->wp ) ) {
|
58 |
+
return true;
|
59 |
+
} else {
|
60 |
+
add_action( 'admin_notices', array( $this, 'wp_version_notice' ) );
|
61 |
+
return false;
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
private static function __wp_at_least( $min_version ) {
|
66 |
+
return version_compare( get_bloginfo( 'version' ), $min_version, '>=' );
|
67 |
+
}
|
68 |
+
|
69 |
+
public function wp_version_notice() {
|
70 |
+
echo '<div class="error">';
|
71 |
+
echo "<p>The “" . esc_html( $this->title ) . "” plugin cannot run on WordPress versions older than " . $this->wp . '. Please update WordPress.</p>';
|
72 |
+
echo '</div>';
|
73 |
+
}
|
74 |
+
}
|
disable-json-api.php
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
/**
|
3 |
* Plugin Name: Disable REST API
|
4 |
* Plugin URI: http://www.binarytemplar.com/disable-json-api
|
5 |
-
* Description: Disable the use of the
|
6 |
-
* Version: 1.
|
7 |
* Author: Dave McHale
|
8 |
* Author URI: http://www.binarytemplar.com
|
9 |
* Text Domain: disable-json-api
|
@@ -22,17 +22,34 @@ function disable_rest_api_load_textdomain() {
|
|
22 |
load_plugin_textdomain( 'disable-json-api', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
|
23 |
}
|
24 |
|
25 |
-
//
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
}
|
|
|
|
2 |
/**
|
3 |
* Plugin Name: Disable REST API
|
4 |
* Plugin URI: http://www.binarytemplar.com/disable-json-api
|
5 |
+
* Description: Disable the use of the REST API on your website to anonymous users
|
6 |
+
* Version: 1.5
|
7 |
* Author: Dave McHale
|
8 |
* Author URI: http://www.binarytemplar.com
|
9 |
* Text Domain: disable-json-api
|
22 |
load_plugin_textdomain( 'disable-json-api', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
|
23 |
}
|
24 |
|
25 |
+
// Requirements check, to cleanly handle failure of WP/PHP version requirements
|
26 |
+
include( dirname( __FILE__ ) . '/classes/requirements-check.php' );
|
27 |
+
|
28 |
+
$dra_requirements_check = new Disable_REST_API_Requirements_Check( array(
|
29 |
+
'title' => 'Disable REST API',
|
30 |
+
'php' => '5.3',
|
31 |
+
'wp' => '4.4',
|
32 |
+
'file' => __FILE__,
|
33 |
+
) );
|
34 |
+
|
35 |
+
// Only load plugin if we pass minimum requirements
|
36 |
+
if ( $dra_requirements_check->passes() ) {
|
37 |
+
|
38 |
+
// Remove REST API info from head and headers
|
39 |
+
remove_action( 'xmlrpc_rsd_apis', 'rest_output_rsd' );
|
40 |
+
remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
|
41 |
+
remove_action( 'template_redirect', 'rest_output_link_header', 11 );
|
42 |
+
|
43 |
+
// WordPress 4.7+ disables the REST API via authentication short-circuit.
|
44 |
+
// For versions of WordPress < 4.7, disable the REST API via filters
|
45 |
+
if ( version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) {
|
46 |
+
require_once( plugin_dir_path( __FILE__ ) . 'classes/disable-rest-api.php' );
|
47 |
+
new Disable_REST_API( __FILE__ );
|
48 |
+
} else {
|
49 |
+
require_once( plugin_dir_path( __FILE__ ) . 'functions/legacy.php' );
|
50 |
+
DRA_Disable_Via_Filters();
|
51 |
+
}
|
52 |
+
|
53 |
}
|
54 |
+
|
55 |
+
unset( $dra_requirements_check );
|
functions/legacy.php
CHANGED
@@ -1,16 +1,16 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* This function gets called if the current version of WordPress is less than 4.7
|
4 |
-
* We are able to make use of filters to actually disable the functionality entirely
|
5 |
-
*/
|
6 |
-
function DRA_Disable_Via_Filters() {
|
7 |
-
|
8 |
-
// Filters for WP-API version 1.x
|
9 |
-
add_filter( 'json_enabled', '__return_false' );
|
10 |
-
add_filter( 'json_jsonp_enabled', '__return_false' );
|
11 |
-
|
12 |
-
// Filters for WP-API version 2.x
|
13 |
-
add_filter( 'rest_enabled', '__return_false' );
|
14 |
-
add_filter( 'rest_jsonp_enabled', '__return_false' );
|
15 |
-
|
16 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* This function gets called if the current version of WordPress is less than 4.7
|
4 |
+
* We are able to make use of filters to actually disable the functionality entirely
|
5 |
+
*/
|
6 |
+
function DRA_Disable_Via_Filters() {
|
7 |
+
|
8 |
+
// Filters for WP-API version 1.x
|
9 |
+
add_filter( 'json_enabled', '__return_false' );
|
10 |
+
add_filter( 'json_jsonp_enabled', '__return_false' );
|
11 |
+
|
12 |
+
// Filters for WP-API version 2.x
|
13 |
+
add_filter( 'rest_enabled', '__return_false' );
|
14 |
+
add_filter( 'rest_jsonp_enabled', '__return_false' );
|
15 |
+
|
16 |
+
}
|
readme.txt
CHANGED
@@ -2,22 +2,26 @@
|
|
2 |
Contributors: dmchale, tangrufus
|
3 |
Tags: admin, api, json, REST, rest-api, disable
|
4 |
Requires at least: 4.4
|
5 |
-
Requires PHP: 5.
|
6 |
-
Tested up to:
|
7 |
-
Stable tag: 1.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
11 |
-
Disable the use of the
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
-
|
16 |
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
21 |
|
22 |
As of WordPress 4.7, the filters provided for disabling the REST API were removed. To compensate, this plugin will
|
23 |
forcibly return an authentication error to any API requests from sources who are not logged into your website, which
|
@@ -53,9 +57,16 @@ disabled so long as this plugin is active. Namespaces and routes may be whitelis
|
|
53 |
|
54 |
1. The JSON returned by a website with the API disabled via filters (WP versions 4.4, 4.5, 4.6)
|
55 |
2. The JSON returned by a website with the API disabled via authentication methods (WP versions 4.7+)
|
|
|
56 |
|
57 |
== Changelog ==
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
= 1.4.3 =
|
60 |
* Added `load_plugin_textdomain()` for i18n
|
61 |
|
2 |
Contributors: dmchale, tangrufus
|
3 |
Tags: admin, api, json, REST, rest-api, disable
|
4 |
Requires at least: 4.4
|
5 |
+
Requires PHP: 5.6
|
6 |
+
Tested up to: 5.3
|
7 |
+
Stable tag: 1.5
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
11 |
+
Disable the use of the REST API on your website to unauthenticated users.
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
+
The most comprehensive plugin for controlling access to the WordPress REST API!
|
16 |
|
17 |
+
Works as a "set it and forget it" install. Just upload and activate, and the entire REST API will be inaccessible to
|
18 |
+
your site visitors. Or if you have a plugin or theme installed which needs some of its endpoints to be accessible to
|
19 |
+
site visitors, you can do that too. Go to the Settings page and you can quickly whitelist individual endpoints - or
|
20 |
+
entire branches of endpoints - registered with the REST API.
|
21 |
+
|
22 |
+
The engine for the API has existed in WordPress since v4.4 and additional functionality and endpoints are a
|
23 |
+
continual project. While this is very exciting news for many reasons, it is also not functionality that every site
|
24 |
+
admin wants enabled on their website if not necessary.
|
25 |
|
26 |
As of WordPress 4.7, the filters provided for disabling the REST API were removed. To compensate, this plugin will
|
27 |
forcibly return an authentication error to any API requests from sources who are not logged into your website, which
|
57 |
|
58 |
1. The JSON returned by a website with the API disabled via filters (WP versions 4.4, 4.5, 4.6)
|
59 |
2. The JSON returned by a website with the API disabled via authentication methods (WP versions 4.7+)
|
60 |
+
3. The Settings page lets you selectively whitelist endpoints registered with the REST API.
|
61 |
|
62 |
== Changelog ==
|
63 |
|
64 |
+
= 1.5 =
|
65 |
+
* Tested up to WP v5.3
|
66 |
+
* Added enforcement for WordPress and PHP minimum version requirements
|
67 |
+
* Fixed minor bug to prevent unintended empty routes
|
68 |
+
* Minor text updates and adding textdomain to translation functions that didn't have them
|
69 |
+
|
70 |
= 1.4.3 =
|
71 |
* Added `load_plugin_textdomain()` for i18n
|
72 |
|