PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.11.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.11.0
2.11.0 2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 All 78 releases
← All changes | Modules/Auth/AuthModdule.php +85 -23 2.7.52.11.0 View file →
@@ -28,8 +28,19 @@
28 28 add_action('wp_ajax_fcom_user_registration', [$this, 'handleUserSignup']);
29 29 add_action('wp_ajax_nopriv_fcom_user_login_form', [$this, 'handleUserLogin']);
30 30 add_action('wp_ajax_fcom_user_login_form', [$this, 'handleUserLogin']);
31 31
32 + /*
33 + * Declared here rather than where the auth screen renders, because the form that
34 + * screen draws posts back to admin-ajax and that is a different request: nothing
35 + * survives into it but what the browser sent. FluentAuth answers those posts only
36 + * for a host it already knows about.
37 + *
38 + * `is_fcom_auth` is the field the login form has always carried; FluentAuth's own
39 + * signed marker travels on the rest.
40 + */
41 + AuthHelper::registerWithFluentAuth();
42 +
32 43 add_filter('fluent_auth/login_redirect_url', function ($redirectUrl, $user) {
33 44 if (empty($_REQUEST['is_fcom_auth']) || empty($_REQUEST['fcom_redirect'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
34 45 return $redirectUrl;
35 46 }
@@ -63,12 +74,52 @@
63 74
64 75 // Remove fcom_action and fcom_url_hash from the current url
65 76 $currentUrl = home_url(add_query_arg($_GET, $GLOBALS['wp']->request)); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
66 77 $url = remove_query_arg(['fcom_action', 'fcom_url_hash'], $currentUrl);
67 - wp_redirect($url, 302); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
78 + $this->redirectAndExit($url);
79 + }
80 +
81 + /**
82 + * Send a redirect and stop.
83 + *
84 + * Extracted only so it can be observed: a bare `exit()` terminates the PHP
85 + * process, which in a test run kills the whole suite with no result (see
86 + * FIX-PLAN item 22 for the same problem on PortalHandler). A test subclass
87 + * overrides this and the two methods below to record what was about to
88 + * happen and throw instead. Behaviour in production is unchanged — this is
89 + * the original call, moved.
90 + *
91 + * This one keeps the UNSAFE variant its single caller already used. That
92 + * caller builds its target with home_url(), so it is same-host by
93 + * construction rather than by validation. Kept as a separate method from
94 + * safeRedirectAndExit(), rather than a $safe flag, so the distinction stays
95 + * visible to anyone grepping for wp_redirect.
96 + */
97 + protected function redirectAndExit($url, $status = 302)
98 + {
99 + wp_redirect($url, $status); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
68 100 exit();
69 101 }
70 102
103 + /**
104 + * Send a host-confined redirect and stop. See redirectAndExit().
105 + */
106 + protected function safeRedirectAndExit($url)
107 + {
108 + wp_safe_redirect($url);
109 + exit();
110 + }
111 +
112 + /**
113 + * Render the headless page and stop. See redirectAndExit().
114 + */
115 + protected function renderPageAndExit($template, $pageVars)
116 + {
117 + status_header(200);
118 + App::make('view')->render($template, $pageVars);
119 + exit(200);
120 + }
121 +
71 122 public function viewAuthPage()
72 123 {
73 124
74 125 add_filter('login_form_defaults', function ($defaults) {
@@ -98,10 +149,9 @@
98 149 if (!$redirectUrl) {
99 150 $redirectUrl = Helper::baseUrl();
100 151 }
101 152
102 - wp_safe_redirect($redirectUrl);
103 - exit();
153 + $this->safeRedirectAndExit($redirectUrl);
104 154 }
105 155
106 156 if ($currentUserId && $inviation) {
107 157 /** @var BaseSpace|null $space */
@@ -109,10 +159,9 @@
109 159 if ($space) {
110 160 if (Helper::isUserInSpace($currentUserId, $inviation->post_id)) {
111 161 // let's redirect the user to the space
112 162 $redirectUrl = $space->getPermalink();
113 - wp_safe_redirect($redirectUrl);
114 - exit();
163 + $this->safeRedirectAndExit($redirectUrl);
115 164 }
116 165
117 166 if (!empty($_REQUEST['auto_accept'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
118 167 $redirectUrl = (new InvitationHandler())->handleInvitationLogin(Helper::baseUrl(), get_user_by('ID', $currentUserId), $inviation->message_rendered);
@@ -118,10 +167,9 @@
118 167 $redirectUrl = (new InvitationHandler())->handleInvitationLogin(Helper::baseUrl(), get_user_by('ID', $currentUserId), $inviation->message_rendered);
119 168 if (is_wp_error($redirectUrl) || !$redirectUrl) {
120 169 $redirectUrl = Helper::baseUrl();
121 170 }
122 - wp_safe_redirect($redirectUrl);
123 - exit();
171 + $this->safeRedirectAndExit($redirectUrl);
124 172 }
125 173 }
126 174 }
127 175
@@ -153,12 +201,21 @@
153 201 $targetForm = 'accept_invitation';
154 202 }
155 203 }
156 204
205 + /*
206 + * Hand the screen to FluentAuth before asking whether it is available: adopting
207 + * is what makes it so. Its front end forms sit behind a site setting meant for
208 + * whether an editor may drop the shortcode into a page, and reading that as
209 + * "may this portal use FluentAuth" is what used to drop us onto a login form of
210 + * our own while FluentAuth went on injecting magic login and enforcing a second
211 + * factor against a DOM it no longer recognised.
212 + */
213 + AuthHelper::adoptFluentAuth();
214 +
157 215 $isFluentAuth = AuthHelper::isFluentAuthAvailable();
158 216 if (!$isFluentAuth && $targetForm == 'reset_password') {
159 - wp_safe_redirect(wp_lostpassword_url(Helper::baseUrl()));
160 - exit();
217 + $this->safeRedirectAndExit(wp_lostpassword_url(Helper::baseUrl()));
161 218 }
162 219
163 220 $portalSettings = Helper::generalSettings();
164 221 $titleVar = Arr::get($portalSettings, 'site_title');
@@ -175,10 +232,9 @@
175 232 $frameData['button_label'] = __('Signup', 'fluent-community');
176 233 if (!$inviation) {
177 234 $customSignupUrl = Arr::get($portalSettings, 'custom_signup_url');
178 235 if ($customSignupUrl) {
179 - wp_safe_redirect($customSignupUrl);
180 - exit();
236 + $this->safeRedirectAndExit($customSignupUrl);
181 237 }
182 238 }
183 239 }
184 240
@@ -191,9 +247,13 @@
191 247 wp_enqueue_script('fluent_auth_scripts', Vite::getStaticSrcUrl('user_registration.js'), [], FLUENT_COMMUNITY_PLUGIN_VERSION, true);
192 248 wp_localize_script('fluent_auth_scripts', 'fluentComRegistration', array(
193 249 'ajax_url' => admin_url('admin-ajax.php'),
194 250 'is_logged_in' => is_user_logged_in(),
195 - 'redirecting_text' => __('Redirecting...', 'fluent-community')
251 + 'redirecting_text' => __('Redirecting...', 'fluent-community'),
252 + 'i18n' => [
253 + 'generic_error' => esc_html__('Something went wrong. Please try again later', 'fluent-community'),
254 + 'network_error' => esc_html__('Could not reach the server. Please check your connection and try again.', 'fluent-community'),
255 + ]
196 256 ));
197 257 }
198 258 }, 10);
199 259
@@ -289,15 +349,20 @@
289 349 }, 10, 1);
290 350
291 351 add_action('fluent_community/headless/head_early', function ($scope) use ($formSettings) {
292 352 $bannerColors = array_filter(Arr::only($formSettings['banner'], ['title_color', 'text_color', 'background_color']));
293 - $css = Utility::getColorCssVariables(); ?>
353 + $css = Utility::getColorCssVariables();
354 +
355 + $sideVars = '';
356 + foreach ($bannerColors as $colorKey => $colorValue) {
357 + $sideVars .= '--fcom_' . $colorKey . ': ' . $colorValue . ';';
358 + }
359 + ?>
360 + <?php // the auth screen renders with load_wp, which skips headless_page's noindex ?>
361 + <meta name="robots" content="noindex, noarchive" />
294 362 <link rel="canonical" href="<?php echo esc_url(Helper::getAuthUrl()); ?>" />
295 363 <style>
296 - .fcom_layout_side {
297 - <?php foreach ($bannerColors as $colorKey => $colorValue): ?> --fcom_ <?php echo esc_html($colorKey); ?>: <?php echo esc_html($colorValue); ?>;
298 - <?php endforeach; ?>
299 - }
364 + .fcom_layout_side { <?php echo esc_html($sideVars); ?> }
300 365 <?php echo esc_html($css); ?>
301 366 </style>
302 367 <?php
303 368 });
@@ -308,11 +373,9 @@
308 373 add_filter('pre_get_document_title', function ($title) use ($frameData) {
309 374 return $frameData['title'];
310 375 }, 9999, 1);
311 376
312 - status_header(200);
313 - App::make('view')->render('headless_page', $pageVars);
314 - exit(200);
377 + $this->renderPageAndExit('headless_page', $pageVars);
315 378 }
316 379
317 380 public function handleUserSignup()
318 381 {
@@ -407,8 +470,9 @@
407 470 ], 422);
408 471 }
409 472
410 473 $data['email'] = sanitize_email($data['email']);
474 + $data['full_name'] = sanitize_text_field(Arr::get($data, 'full_name', ''));
411 475
412 476 $validations = [
413 477 'full_name' => 'required|max:100|string',
414 478 'username' => 'required|unique:users,user_login|unique:fcom_xprofile,username|min:4|max:30',
@@ -854,12 +918,10 @@
854 918 add_action('fluent_community/before_registration_form', function ($frameData) {
855 919 if (AuthHelper::isFluentAuthAvailable()) {
856 920 $currentUrl = esc_url(home_url(add_query_arg($_GET, $GLOBALS['wp']->request))); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
857 921
858 - ob_start();
859 922 $titlePrefix = __('Signup with', 'fluent-community');
860 - do_shortcode('[fs_auth_buttons redirect="' . $currentUrl . '" title_prefix="' . $titlePrefix . ' " title=""]');
861 - $html = ob_get_clean();
923 + $html = do_shortcode('[fs_auth_buttons redirect="' . $currentUrl . '" title_prefix="' . $titlePrefix . ' " title=""]');
862 924
863 925 if ($html) {
864 926 echo '<div class="fcom_social_auth_wrap">';
865 927 echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped