/** * Check that the user has sufficient permissions, or die in error * */ private function _checkPermissions() { // Is frontend backup enabled? $febEnabled = Platform::getInstance()->get_platform_configuration_option('failure_frontend_enable', 0) != 0; // Is the Secret Key strong enough? $validKey = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', ''); if (!\Akeeba\Engine\Util\Complexify::isStrongEnough($validKey, false)) { $febEnabled = false; } if (!$febEnabled) { @ob_end_clean(); echo '403 ' . JText::_('ERROR_NOT_ENABLED'); flush(); JFactory::getApplication()->close(); } // Is the key good? $key = $this->input->get('key', '', 'none', 2); $validKeyTrim = trim($validKey); if ($key != $validKey || empty($validKeyTrim)) { @ob_end_clean(); echo '403 ' . JText::_('ERROR_INVALID_KEY'); flush(); JFactory::getApplication()->close(); } }
/** * Parses the JSON data sent by the client and executes the appropriate JSON API task * * @param string $json The raw JSON data received from the remote client * * @return string The JSON-encoded, fully encapsulated response */ public function execute($json) { // Check if we're activated $enabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0); // Is the Secret Key strong enough? $validKey = $this->serverKey(); if (!Complexify::isStrongEnough($validKey, false)) { $enabled = false; } $rawEncapsulation = $this->encapsulation->getEncapsulationByCode('ENCAPSULATION_RAW'); if (!$enabled) { return $this->getResponse('Access denied', 503); } // Try to JSON-decode the request's input first $request = @json_decode($json, true); if (is_null($request)) { return $this->getResponse('JSON decoding error', 500); } // Transform legacy requests if (!is_array($request)) { $request = array('encapsulation' => $rawEncapsulation, 'body' => $request); } // Transform partial requests if (!isset($request['encapsulation'])) { $request['encapsulation'] = $rawEncapsulation; } // Make sure we have a request body if (!isset($request['body'])) { $request['body'] = ''; } try { $request['body'] = $this->encapsulation->decode($request['encapsulation'], $request['body']); } catch (\Exception $e) { return $this->getResponse($e->getMessage(), $e->getCode()); } // Replicate the encapsulation preferences of the client for our own output $this->encapsulationType = $request['encapsulation']; // Store the client-specified key, or use the server key if none specified and the request // came encrypted. $this->password = isset($request['body']['key']) ? $request['body']['key'] : $this->serverKey(); // Run the method $params = array(); if (isset($request['body']['data'])) { $params = (array) $request['body']['data']; } try { $taskHandler = new Task($this->container); $data = $taskHandler->execute($request['body']['method'], $params); } catch (\RuntimeException $e) { return $this->getResponse($e->getMessage(), $e->getCode()); } return $this->getResponse($data); }
/** * Check that the user has sufficient permissions to access the front-end backup feature. * * @return void */ protected function checkPermissions() { // Is frontend backup enabled? $febEnabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0) != 0; // Is the Secret Key strong enough? $validKey = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', ''); $validKeyTrim = trim($validKey); if (!Complexify::isStrongEnough($validKey, false)) { $febEnabled = false; } // Is the key good? $key = $this->input->get('key', '', 'none', 2); if (!$febEnabled || $key != $validKey || empty($validKeyTrim)) { @ob_end_clean(); echo '403 ' . JText::_('COM_AKEEBA_COMMON_ERR_NOT_ENABLED'); flush(); $this->container->platform->closeApplication(); } }
public function execute($json) { // Check if we're activated $enabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0); // Is the Secret Key strong enough? $validKey = $this->serverKey(); if (!\Akeeba\Engine\Util\Complexify::isStrongEnough($validKey, false)) { $enabled = false; } if (!$enabled) { $this->data = 'Access denied'; $this->status = self::STATUS_NOT_AVAILABLE; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Try to JSON-decode the request's input first $request = @json_decode($json, false); if (is_null($request)) { // Could not decode JSON $this->data = 'JSON decoding error'; $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Decode the request body // Request format: {encapsulation, body{ [key], [challenge], method, [data] }} or {[challenge], method, [data]} if (isset($request->encapsulation) && isset($request->body)) { if (!class_exists('\\Akeeba\\Engine\\Util\\Encrypt') && !($request->encapsulation == self::ENCAPSULATION_RAW)) { // Encrypted request found, but there is no encryption class available! $this->data = 'This server does not support encrypted requests'; $this->status = self::STATUS_NOT_AVAILABLE; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Fully specified request $body = ''; switch ($request->encapsulation) { case self::ENCAPSULATION_AESCBC128: if (!isset($body)) { $request->body = base64_decode($request->body); $body = Factory::getEncryption()->AESDecryptCBC($request->body, $this->serverKey(), 128); } break; case self::ENCAPSULATION_AESCBC256: if (!isset($body)) { $request->body = base64_decode($request->body); $body = Factory::getEncryption()->AESDecryptCBC($request->body, $this->serverKey(), 256); } break; case self::ENCAPSULATION_AESCTR128: if (!isset($body)) { $body = Factory::getEncryption()->AESDecryptCtr($request->body, $this->serverKey(), 128); } break; case self::ENCAPSULATION_AESCTR256: if (!isset($body)) { $body = Factory::getEncryption()->AESDecryptCtr($request->body, $this->serverKey(), 256); } break; case self::ENCAPSULATION_RAW: $body = $request->body; break; } if (!empty($request->body)) { $authorised = true; $body = rtrim($body, chr(0)); // Make sure it looks like a valid JSON string and is at least 12 characters (minimum valid message length) if (strlen($body) < 12 || substr($body, 0, 1) != '{' || substr($body, -1) != '}') { $authorised = false; } // Try to JSON decode the body if ($authorised) { $request->body = json_decode($body); if (is_null($request->body)) { $authorised = false; } elseif (!is_object($request->body)) { $authorised = false; } } // Make sure there is a requested method if ($authorised) { if (!isset($request->body->method) || empty($request->body->method)) { $authorised = false; } } if (!$authorised) { // Decryption failed. The user is an impostor! Go away, hacker! $this->data = 'Authentication failed'; $this->status = self::STATUS_NOT_AUTH; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } } } elseif (isset($request->body)) { // Partially specified request, assume RAW encapsulation $request->encapsulation = self::ENCAPSULATION_RAW; $request->body = json_decode($request->body); } else { // Legacy request $legacyRequest = clone $request; $request = (object) array('encapsulation' => self::ENCAPSULATION_RAW, 'body' => null); $request->body = json_decode($legacyRequest); unset($legacyRequest); } // Authenticate the user. Do note that if an encrypted request was made, we can safely assume that // the user is authenticated (he already knows the server key!) if ($request->encapsulation == self::ENCAPSULATION_RAW) { $authenticated = false; if (isset($request->body->challenge)) { list($challenge, $check) = explode(':', $request->body->challenge); $crosscheck = strtolower(md5($challenge . $this->serverKey())); $authenticated = $crosscheck == $check; } if (!$authenticated) { // If the challenge was missing or it was wrong, don't let him go any further $this->data = 'Invalid login credentials'; $this->status = self::STATUS_NOT_AUTH; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } } // Replicate the encapsulation preferences of the client for our own output $this->encapsulation = $request->encapsulation; // Store the client-specified key, or use the server key if none specified and the request // came encrypted. $this->password = isset($request->body->key) ? $request->body->key : null; $hasKey = isset($request->body->key) || property_exists($request->body, 'key') ? !is_null($request->body->key) : false; if (!$hasKey && $request->encapsulation != self::ENCAPSULATION_RAW) { $this->password = $this->serverKey(); } // Does the specified method exist? $method_exists = false; $method_name = ''; if (isset($request->body->method)) { $method_name = ucfirst($request->body->method); $this->method_name = $method_name; $method_exists = method_exists($this, '_api' . $method_name); } if (!$method_exists) { // The requested method doesn't exist. Oops! $this->data = "Invalid method {$method_name}"; $this->status = self::STATUS_INVALID_METHOD; $this->encapsulation = self::ENCAPSULATION_RAW; return $this->getResponse(); } // Run the method $params = array(); if (isset($request->body->data)) { $params = (array) $request->body->data; } $this->data = call_user_func(array($this, '_api' . $method_name), $params); return $this->getResponse(); }
/** * Check the strength of the Secret Word for front-end and remote backups. If it is insecure return the reason it * is insecure as a string. If the Secret Word is secure return an empty string. * * @return string */ public function getFrontendSecretWordError() { // Is frontend backup enabled? $febEnabled = Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0) != 0; if (!$febEnabled) { return ''; } $secretWord = Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', ''); try { \Akeeba\Engine\Util\Complexify::isStrongEnough($secretWord); } catch (RuntimeException $e) { // Ah, the current Secret Word is bad. Create a new one if necessary. $session = JFactory::getSession(); $newSecret = $session->get('newSecretWord', null, 'akeeba.cpanel'); if (empty($newSecret)) { $random = new \Akeeba\Engine\Util\RandomValue(); $newSecret = $random->generateString(32); $session->set('newSecretWord', $newSecret, 'akeeba.cpanel'); } return $e->getMessage(); } return ''; }
/** * Check the strength of the Secret Word for front-end and remote scans. If it is insecure return the reason it * is insecure as a string. If the Secret Word is secure return an empty string. * * @return string */ public function getFrontendSecretWordError() { // Load the Akeeba Engine autoloader define('AKEEBAENGINE', 1); require_once JPATH_ADMINISTRATOR . '/components/com_admintools/engine/Autoloader.php'; // Load the platform \Akeeba\Engine\Platform::addPlatform('filescan', JPATH_ADMINISTRATOR . '/components/com_admintools/platform/Filescan'); // Is frontend backup enabled? $febEnabled = \Akeeba\Engine\Platform::getInstance()->get_platform_configuration_option('frontend_enable', 0) != 0; if (!$febEnabled) { return ''; } $secretWord = \Akeeba\Engine\Platform::getInstance()->get_platform_configuration_option('frontend_secret_word', ''); try { \Akeeba\Engine\Util\Complexify::isStrongEnough($secretWord); } catch (RuntimeException $e) { // Ah, the current Secret Word is bad. Create a new one if necessary. $session = JFactory::getSession(); $newSecret = $session->get('newSecretWord', null, 'admintools.cpanel'); if (empty($newSecret)) { $random = new \Akeeba\Engine\Util\RandomValue(); $newSecret = $random->generateString(32); $session->set('newSecretWord', $newSecret, 'admintools.cpanel'); } return $e->getMessage(); } return ''; }