PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / trunk
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions vtrunk
260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 120219 120301 All 187 releases
s2member / src / includes / classes / security-rest.inc.php

security-rest.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions trunk, at src/includes/classes/security-rest.inc.php

339 lines 17.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * s2Member's Security Gate for REST requests.
5 *
6 * Copyright: © 2009-2024
7 * {@link https://wpsharks.com/ WP Sharks}
8 * (coded in the Switzerland)
9 *
10 * Released under the terms of the GNU General Public License.
11 * You should have received a copy of the GNU General Public License,
12 * along with this software. In the main directory, see: /licensing/
13 * If not, see: {@link http://www.gnu.org/licenses/}.
14 *
15 * @package s2Member\Security
16 * @since 240312
17 */
18 if(!defined('WPINC')) // MUST have WordPress.
19 exit('Do not access this file directly.');
20
21 if(!class_exists('c_ws_plugin__s2member_security_rest'))
22 {
23 /**
24 * s2Member's Security Gate for REST requests.
25 *
26 * @package s2Member\Security
27 * @since 240312
28 */
29 class c_ws_plugin__s2member_security_rest
30 {
31 /**
32 * s2Member's Security Gate (protects WordPress content).
33 *
34 * @package s2Member\Security
35 * @since 240312
36 *
37 * @attaches-to ``add_filter('rest_pre_dispatch');``
38 *
39 * @return null May give a 403 error *(exiting script execution)*, when/if content is NOT available to the current User/Member.
40 */
41 public static function security_gate($response, $handler, $request) // s2Member's Security Gate.
42 {
43 $route = $request->get_route(); // e.g. /wp/v2/pages
44 $route = explode('/', trim($route, '/'));
45
46 if (empty($route[2]) || empty($route[3]))
47 return $response;
48
49 $type = sanitize_key($route[2]); // e.g. pages
50 $id = (int)$route[3];
51
52 $s2_options = $GLOBALS['WS_PLUGIN__']['s2member']['o'];
53 $s2_levels = $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels'];
54 $ci = $s2_options['ruris_case_sensitive'] ? '' : 'i';
55
56 $user = (is_user_logged_in() && is_object($user = wp_get_current_user()) && !empty($user->ID)) ? $user : FALSE;
57
58
59 // Skip early?
60 if (empty($s2_options['membership_options_page'])
61 || empty($id)
62 || $s2_options['membership_options_page'] == $id
63 || c_ws_plugin__s2member_systematics::is_wp_systematic_use_page()) {
64 return $response;
65 }
66
67
68 // Post types array
69 // Use: in_array($type, $post_types, true)
70 $post_types = get_post_types(['show_in_rest' => true], 'names');
71
72 // Get the regular path for this content, to check URI restriction
73 $path = $_SERVER['REQUEST_URI']; // default
74 if (in_array($type, ['posts', 'pages'], true)
75 || in_array($type, $post_types, true)) {
76 $permalink = get_permalink($id);
77 if (!is_wp_error($permalink)) {
78 $path = str_replace(home_url(), '', $permalink);
79 }
80 } elseif ($type === 'categories') {
81 $term_link = get_term_link($id, 'category');
82 if (!is_wp_error($term_link)) {
83 $path = str_replace(home_url(), '', $term_link);
84 }
85 } elseif ($type === 'tags') {
86 $term_link = get_term_link($id, 'post_tag');
87 if (!is_wp_error($term_link)) {
88 $path = str_replace(home_url(), '', $term_link);
89 }
90 }
91
92
93 // Login welcome page
94 if($s2_options['login_welcome_page']
95 && $id === (int)$s2_options['login_welcome_page']
96 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
97 && (!$user || !$user->has_cap('access_s2member_level0'))
98 && $id !== (int)$s2_options['membership_options_page'])
99 return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 'text-domain'), array('status' => 403));
100
101 // Login redirection override
102 else if($s2_options['login_redirection_override']
103 && ($login_redirection_uri = c_ws_plugin__s2member_login_redirects::login_redirection_uri($user, 'root-returns-false'))
104 && preg_match('/^'.preg_quote($login_redirection_uri, '/').'$/'.$ci, $path)
105 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
106 && (!$user || !$user->has_cap('access_s2member_level0'))
107 && $id !== (int)$s2_options['membership_options_page'])
108 return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 'text-domain'), array('status' => 403));
109
110 // File download limit exceeded page
111 else if($s2_options['file_download_limit_exceeded_page']
112 && $id === (int)$s2_options['file_download_limit_exceeded_page']
113 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
114 && (!$user || !$user->has_cap('access_s2member_level0'))
115 && $id !== (int)$s2_options['membership_options_page'])
116 return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 'text-domain'), array('status' => 403));
117
118 // Do NOT protect Systematics (exceptions above)
119 if (c_ws_plugin__s2member_systematics::is_systematic_use_page()) {
120 return $response;
121 }
122
123
124
125 // Categories & other inclusives.
126 if($type == 'categories') {
127 for($n = $s2_levels; $n >= 0; $n--)
128 {
129 // "all"
130 if($s2_options['level'.$n.'_catgs'] === 'all'
131 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
132 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
133 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 'text-domain'), $n), array('status' => 403));
134
135 // This specific categ
136 else if($s2_options['level'.$n.'_catgs']
137 && in_array($id, ($catgs = preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs'])))
138 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
139 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
140 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 'text-domain'), $n), array('status' => 403));
141
142 // Check parent categs
143 else if($s2_options['level'.$n.'_catgs'] /* Check Category ancestry. */)
144 foreach(preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs']) as $catg)
145 if($catg
146 && cat_is_ancestor_of($catg, $id)
147 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
148 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
149 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 'text-domain'), $n), array('status' => 403));
150 }
151 }
152
153
154 // Post/Page Tags & other inclusives.
155 else if($type == 'tags') {
156 for($n = $s2_levels; $n >= 0; $n--) // Tag Level restrictions. Go through each Level.
157 {
158 // "all"
159 if($s2_options['level'.$n.'_ptags'] === 'all'
160 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
161 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
162 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this tag. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
163
164 // This tag
165 else if($s2_options['level'.$n.'_ptags']
166 && ($level_ptags = preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']))
167 && ($tag = get_tag($id))
168 && !empty($tag->name)
169 && in_array($tag->name, $level_ptags)
170 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
171 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
172 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this tag. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
173 }
174 }
175
176
177 // All Posts & other inclusives.
178 else if($type == 'posts'
179 || in_array($type, $post_types, true)) {
180 // Post Level restrictions.
181 for($n = $s2_levels; $n >= 0; $n--)
182 {
183 if($s2_options['level'.$n.'_posts'] === 'all'
184 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
185 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
186 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 'text-domain'), $n), array('status' => 403));
187
188 // what about custom post types?
189 else if(strpos($s2_options['level'.$n.'_posts'], 'all-') !== FALSE
190 && (in_array('all-'.$type, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])) || in_array('all-'.$type.'s', preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])))
191 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
192 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
193 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 'text-domain'), $n), array('status' => 403));
194
195 // a specific post by ID
196 else if($s2_options['level'.$n.'_posts']
197 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts']))
198 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
199 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
200 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 'text-domain'), $n), array('status' => 403));
201 }
202
203 // Category Level restrictions.
204 for($n = $s2_levels; $n >= 0; $n--)
205 {
206 if($s2_options['level'.$n.'_catgs'] === 'all'
207 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
208 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
209 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [catg level %d]', 'text-domain'), $n), array('status' => 403));
210
211 else if($s2_options['level'.$n.'_catgs']
212 && ($catgs = preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs']))
213 && (in_category($catgs, $id) || c_ws_plugin__s2member_utils_conds::in_descendant_category($catgs, $id))
214 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
215 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
216 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [catg level %d]', 'text-domain'), $n), array('status' => 403));
217 }
218
219 if(has_term('', 'post_tag', $id)) // Here we take a look to see if this Post has any Tags. If so, we need to run the full set of routines against Tags also.
220 {
221 for($n = $s2_levels; $n >= 0; $n--) // Tag Level restrictions.
222 {
223 if($s2_options['level'.$n.'_ptags'] === 'all'
224 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
225 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
226 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
227
228 else if($s2_options['level'.$n.'_ptags']
229 && has_tag(preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']), $id)
230 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
231 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
232 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
233 }
234 }
235
236 if(is_array($ccaps_req = get_post_meta($id, 's2member_ccaps_req', TRUE))
237 && !empty($ccaps_req)
238 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted'))
239 {
240 foreach($ccaps_req as $ccap) // The ``$user`` MUST satisfy ALL Custom Capability requirements. Stored as an array of Custom Capabilities.
241 if(strlen($ccap)
242 && (!$user || !$user->has_cap('access_s2member_ccap_'.$ccap)) /* Does this ``$user``, have this Custom Capability? */)
243 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ccap %s]', 'text-domain'), $ccap), array('status' => 403));
244 }
245
246 if($s2_options['specific_ids']
247 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['specific_ids']))
248 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
249 && !c_ws_plugin__s2member_sp_access::sp_access($id))
250 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [sp %d]', 'text-domain'), $id), array('status' => 403));
251
252 }
253
254
255 // All Pages & other inclusives.
256 else if($type == 'pages') {
257 for($n = $s2_levels; $n >= 0; $n--) // Page Level restrictions. Go through each Level.
258 {
259 // "all"
260 if($s2_options['level'.$n.'_pages'] === 'all'
261 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
262 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
263 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 'text-domain'), $n), array('status' => 403));
264
265 // "all" of custom post type "page"
266 else if(strpos($s2_options['level'.$n.'_posts'], 'all-')
267 && (in_array('all-page', preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])) || in_array('all-pages', preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])))
268 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
269 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
270 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 'text-domain'), $n), array('status' => 403));
271
272 // Current page ID
273 else if($s2_options['level'.$n.'_pages']
274 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_pages']))
275 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
276 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
277 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 'text-domain'), $n), array('status' => 403));
278 }
279
280 // Tag restriction
281 if(has_term('', 'post_tag', $id)) // Here we take a look to see if this Page has any Tags. If so, we need to run the full set of routines against Tags also.
282 {
283 for($n = $s2_levels; $n >= 0; $n--) // Tag Level restrictions (possibly through Page Tagger). Go through each Level.
284 {
285 // "all" tags
286 if($s2_options['level'.$n.'_ptags'] === 'all'
287 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
288 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
289 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
290
291 // Has a restricted tag
292 else if($s2_options['level'.$n.'_ptags']
293 && has_tag(preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']), $id)
294 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
295 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
296 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
297 }
298 }
299
300 // Custom Capabilities
301 if(is_array($ccaps_req = get_post_meta($id, 's2member_ccaps_req', TRUE))
302 && !empty($ccaps_req)
303 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted'))
304 {
305 foreach($ccaps_req as $ccap) // The ``$user`` MUST satisfy ALL Custom Capability requirements. Stored as an array of Custom Capabilities.
306 if(strlen($ccap)
307 && (!$user || !$user->has_cap('access_s2member_ccap_'.$ccap)) /* Does this ``$user``, have this Custom Capability? */)
308 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ccap %s]', 'text-domain'), $ccap), array('status' => 403));
309 }
310
311 // Specific Page restriction
312 if($s2_options['specific_ids']
313 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['specific_ids']))
314 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
315 && !c_ws_plugin__s2member_sp_access::sp_access($id))
316 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [sp %d]', 'text-domain'), $id), array('status' => 403));
317
318 }
319
320
321 // Also check URIs & other inclusives.
322 for($n = $s2_levels; $n >= 0; $n--) // URIs. Go through each Level.
323 {
324 // URI restriction
325 if($s2_options['level'.$n.'_ruris']) // URIs configured at this Level?
326 foreach(preg_split('/['."\r\n\t".']+/', c_ws_plugin__s2member_ruris::fill_ruri_level_access_rc_vars($s2_options['level'.$n.'_ruris'], $user)) as $str) {
327 if($str
328 && preg_match('/'.preg_quote($str, '/').'/'.$ci, $path)
329 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
330 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
331 return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this content. [ruri level %d]', 'text-domain'), $n), array('status' => 403));
332 }
333 }
334
335 return $response;
336 }
337 }
338 }
339