reachabilityService = new ReachabilityService(); } /** * Public, unauthenticated: the SaaS calls this to confirm it can reach us. * * It cannot reuse /ping — that route sits behind AuthSaasMiddleware, which * needs a site UID and secret, and neither exists before the site connects. * The single-use challenge is what authenticates this request. */ public function challenge($request) : Response { $challenge = (string) $request->get_param('challenge'); if ($challenge === '' || !$this->reachabilityService->matchesChallenge($challenge)) { return Helper::rvxApi()->fails(\__('Unknown challenge', 'reviewx'), Response::HTTP_FORBIDDEN); } return Helper::rvxApi(['challenge' => $challenge, 'wp_version' => \get_bloginfo('version'), 'plugin_version' => REVIEWX_VERSION])->success(\__('Site reachable', 'reviewx'), Response::HTTP_OK); } /** * Run the check when the onboarding screen loads. * * Public, like the sibling /login and /register routes: the admin UI calls * the REST API without a nonce or bearer token, so nothing here can identify * the caller. The endpoint is safe to leave open — it takes no target from * the request (the URL probed is always this site's own home_url) and repeat * calls are served from the cached verdict. * * Only a caller WordPress can actually identify may force a fresh probe, so * an anonymous caller cannot drive outbound traffic. */ public function verify($request) : Response { $force = (bool) $request->get_param('force') && \current_user_can('manage_options'); $result = $this->reachabilityService->check($force); return Helper::rvxApi($result)->success($result['message'], Response::HTTP_OK); } }