/** * Invoke a tool session * * @return void */ public function invokeTask() { // Check that the user is logged in if (User::isGuest()) { $this->loginTask(); return; } $params = Request::getString('params', '', 'default', JREQUEST_ALLOWRAW); if (!empty($params)) { $params_whitelist = explode(',', $this->config->get('params_whitelist', '')); $separator = "\r\n"; $line = trim(strtok($params, $separator)); $verified_params = array(); while ($line !== false) { $re = "/\\s*(directory|file|int)\\s*(?:\\:|\\(\\s*(.*?)\\s*\\)\\s*:)\\s*(.*?)\\s*\$/"; if (preg_match($re, $line, $matches) != false) { $type = $matches[1]; $key = $matches[2]; $value = $matches[3]; if ($type == 'directory' || $type == 'file') { // Replace ~/ prefix with user's home directory if (strncmp($value, "~/", 2) === 0) { $homeDirectory = rtrim(User::get('homeDirectory'), '/'); if (!isset($homeDirectory[0]) || $homeDirectory[0] !== '/') { break; } $value = substr_replace($value, $homeDirectory, 0, 1); } // Fail if $value doesn't start with '/' if ($value[0] != '/') { break; } // Fail if unable to normalize $value $value = $this->normalize_path($value, $type == 'file'); if ($value === false) { break; } // Fail if $value contains a control charcater (0x00-0x1F) or an invalid utf-8 string if (preg_match('/^[^\\x00-\\x1f]*$/u', $value) == 0) { break; } // Fail if whitelist is empty if (empty($params_whitelist)) { break; } // Fail if $value isn't prefixed with a whitelisted directory foreach ($params_whitelist as $wl) { if (empty($wl)) { continue; } $wl = rtrim(trim($wl), '/') . '/'; // make sure we compare against a full path element if (strncmp($wl, $value, strlen($wl)) === 0) { $match = $wl; break; } } if (!isset($match)) { break; } // Add verified parameter to array if ($key) { $verified_params[] = $type . '(' . $key . '):' . $value; } else { $verified_params[] = $type . ':' . $value; } } else { if ($type == 'int') { // Fail if $value contains a control charcater (0x00-0x1F) or an invalid utf-8 string if (preg_match('/^[^\\x00-\\x1f]*$/u', $value) == 0) { break; } // Fail if $value not an integer if (preg_match('/^[-+]?[0-9]+$/', $value) == 0) { break; } // Add verified parameter to array if ($key) { $verified_params[] = $type . '(' . $key . '):' . $value; } else { $verified_params[] = $type . ':' . $value; } } } } else { if (!empty($line)) { break; } } $line = strtok($separator); // Get next line } if ($line !== false) { $this->badparamsTask($params); return; } } // Incoming $app = new stdClass(); $app->name = trim(str_replace(':', '-', Request::getVar('app', ''))); //$app->number = 0; $app->version = Request::getVar('version', 'default'); // Get the user's IP address $app->ip = Request::ip(); // Make sure we have an app to invoke if (!$app->name) { App::redirect(Route::url($this->config->get('stopRedirect', 'index.php?option=com_members&task=myaccount'))); return; } // Get the parent toolname (appname without any revision number "_r423") include_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'version.php'; $tv = new \Components\Tools\Tables\Version($this->database); switch ($app->version) { case 1: case 'current': case 'default': $app->name = $tv->getCurrentVersionProperty($app->name, 'instance'); break; case 'test': case 'dev': $app->name .= '_dev'; break; default: $app->name .= '_r' . $app->version; break; } $app->toolname = $app->name; if ($parent = $tv->getToolname($app->name)) { $app->toolname = $parent; } // Check of the toolname has a revision indicator $r = substr(strrchr($app->name, '_'), 1); if (substr($r, 0, 1) != 'r' && substr($r, 0, 3) != 'dev') { $r = ''; } // No version passed and no revision if ((!$app->version || $app->version == 'default' || $app->version == 'current') && !$r) { // Get the latest version $app->version = $tv->getCurrentVersionProperty($app->toolname, 'revision'); $app->name = $app->toolname . '_r' . $app->version; } // Get the caption/session title $tv->loadFromInstance($app->name); $app->caption = stripslashes($tv->title); $app->title = stripslashes($tv->title); // Check if they have access to run this tool $hasaccess = $this->_getToolAccess($app->name); //$status2 = ($hasaccess) ? "PASSED" : "FAILED"; //Log::debug("mw::invoke " . $app->name . " by " . User::get('username') . " from " . $app->ip . " _getToolAccess " . $status2); if ($this->getError()) { echo '<!-- ' . $this->getError() . ' -->'; } if (!$hasaccess) { //$this->_redirect = Route::url('index.php?option=' . $this->_option . '&task=accessdenied'); $this->app = $app; $this->accessdeniedTask(); return; } $country = \Hubzero\Geocode\Geocode::ipcountry($app->ip); //die($app->ip . $country); // Log the launch attempt $this->_recordUsage($app->toolname, User::get('id')); // Get the middleware database $mwdb = \Components\Tools\Helpers\Utils::getMWDBO(); // Find out how many sessions the user is running. $ms = new \Components\Tools\Tables\Session($mwdb); $jobs = $ms->getCount(User::get('username')); // Find out how many sessions the user is ALLOWED to run. include_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'preferences.php'; $preferences = new \Components\Tools\Tables\Preferences($this->database); $preferences->loadByUser(User::get('id')); if (!$preferences || !$preferences->id) { include_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'sessionclass.php'; $scls = new \Components\Tools\Tables\SessionClass($this->database); $default = $scls->find('one', array('alias' => 'default')); $preferences->user_id = User::get('id'); $preferences->class_id = $default->id; $preferences->jobs = $default->jobs ? $default->jobs : 3; $preferences->store(); } $remain = $preferences->jobs - $jobs; // Have they reached their session quota? if ($remain <= 0) { $this->quotaexceededTask(); return; } if ($this->config->get('warn_multiples', 0) && !Request::getInt('newinstance', 0)) { $sessions = $ms->getRecords(User::get('username'), $app->name, false); if ($sessions && count($sessions) > 0) { $this->view->setLayout('list'); $this->view->app = $app; $this->view->config = $this->config; $this->view->sessions = $sessions; foreach ($this->getErrors() as $error) { $view->setError($error); } $this->view->display(); return; } } // Get their disk space usage $this->_getDiskUsage(); $this->_redirect = ''; $app->percent = 0; if ($this->config->get('show_storage', 1)) { $app->percent = $this->percent; } if ($this->percent >= 100) { App::redirect(Route::url('index.php?option=' . $this->_option . '&controller=storage')); return; } // Get plugins Plugin::import('mw', $app->toolname); // Trigger any events that need to be called before session invoke Event::trigger('mw.onBeforeSessionInvoke', array($app->toolname, $app->version)); $toolparams = ''; if (!empty($params)) { $toolparams = " params=" . rawurlencode($params) . " "; } // Determine zone $app->zone_id = 0; if ($this->config->get('zones')) { $middleware = new \Components\Tools\Models\Middleware(); $this->database->setQuery("SELECT zone_id FROM `#__tool_version_zone` WHERE tool_version_id=" . $this->database->quote($tv->id)); $middleware->set('allowed', $this->database->loadColumn()); if ($zone = $middleware->zoning($app->ip, $middleware->get('allowed'))) { if ($zone->exists()) { $toolparams .= ' zone=' . $zone->get('zone'); $app->zone_id = $zone->get('id'); } } } // We've passed all checks so let's actually start the session $status = $this->middleware("start user="******" ip=" . $app->ip . " app=" . $app->name . " version=" . $app->version . $toolparams, $output); if ($this->getError()) { //App::abort(500, $this->getError()); //return; App::redirect(Route::url($this->config->get('stopRedirect', 'index.php?option=com_members&task=myaccount')), Lang::txt('COM_TOOLS_ERROR_SESSION_INVOKE_FAILED'), 'error'); return; } $app->sess = !empty($output->session) ? $output->session : ''; // Trigger any events that need to be called after session invoke Event::trigger('mw.onAfterSessionInvoke', array($app->toolname, $app->version)); // Get a count of the number of sessions of this specific tool $appcount = $ms->getCount(User::get('username'), $app->name); // Do we have more than one session of this tool? if ($appcount > 1) { // We do, so let's append a timestamp $app->caption .= ' (' . Date::toLocal('g:i a') . ')'; } // Save the changed caption $ms->load($app->sess); $ms->sessname = $app->caption; $ms->params = $params; if (!$ms->store()) { App::abort(500, $ms->getError()); } $rtrn = Request::getVar('return', ''); $url = 'index.php?option=' . $this->_option . '&controller=' . $this->_controller . '&app=' . $app->toolname . '&task=session&sess=' . $app->sess . '&return=' . $rtrn . (Request::getWord('viewer') ? '&viewer=' . Request::getWord('viewer') : ''); // Log activity Event::trigger('system.logActivity', ['activity' => ['action' => 'created', 'scope' => 'tool.session', 'scope_id' => $app->sess, 'description' => Lang::txt('COM_TOOLS_ACTIVITY_SESSION_CREATED', $app->sess, '<a href="' . Route::url($url) . '">' . $app->caption . '</a>'), 'details' => array('tool' => $app->name, 'url' => $url)], 'recipients' => array(['user', User::get('id')])]); App::redirect(Route::url($url, false)); }
/** * Method to invoke new tools session * * @apiMethod GET * @apiUri /tools/{tool}/invoke * @return void */ public function invokeTask() { //get the userid and attempt to load user profile $userid = App::get('authn')['user_id']; $result = User::getInstance($userid); //make sure we have a user if (!$result->get('id')) { throw new Exception(Lang::txt('Unable to find user.'), 404); } //get request vars $tool_name = Request::getVar('app', ''); $tool_version = Request::getVar('version', 'default'); //build application object $app = new stdClass(); $app->name = trim(str_replace(':', '-', $tool_name)); $app->version = $tool_version; $app->ip = $_SERVER["REMOTE_ADDR"]; //check to make sure we have an app to invoke if (!$app->name) { $this->errorMessage(400, 'You Must Supply a Valid Tool Name to Invoke.'); return; } //include needed tool libraries include_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'version.php'; require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'session.php'; require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'viewperm.php'; //create database object $database = \App::get('db'); //load the tool version $tv = new \Components\Tools\Tables\Version($database); switch ($app->version) { case 1: case 'default': $app->name = $tv->getCurrentVersionProperty($app->name, 'instance'); break; case 'test': case 'dev': $app->name .= '_dev'; break; default: $app->name .= '_r' . $app->version; break; } $app->toolname = $app->name; if ($parent = $tv->getToolname($app->name)) { $app->toolname = $parent; } // Check of the toolname has a revision indicator $r = substr(strrchr($app->name, '_'), 1); if (substr($r, 0, 1) != 'r' && substr($r, 0, 3) != 'dev') { $r = ''; } // No version passed and no revision if ((!$app->version || $app->version == 'default') && !$r) { // Get the latest version $app->version = $tv->getCurrentVersionProperty($app->toolname, 'revision'); $app->name = $app->toolname . '_r' . $app->version; } // Get the caption/session title $tv->loadFromInstance($app->name); $app->caption = stripslashes($tv->title); $app->title = stripslashes($tv->title); //make sure we have a valid tool if ($app->title == '' || $app->toolname == '') { throw new Exception(Lang::txt('The tool "%s" does not exist on the HUB.', $tool_name), 400); } //get tool access $toolAccess = \Components\Tools\Helpers\Utils::getToolAccess($app->name, $result->get('username')); //do we have access if ($toolAccess->valid != 1) { throw new Exception($toolAccess->error->message, 400); } // Log the launch attempt \Components\Tools\Helpers\Utils::recordToolUsage($app->toolname, $result->get('id')); // Get the middleware database $mwdb = \Components\Tools\Helpers\Utils::getMWDBO(); // Find out how many sessions the user is running. $ms = new \Components\Tools\Models\Middleware\Session($mwdb); $jobs = $ms->getCount($result->get('username')); // Find out how many sessions the user is ALLOWED to run. include_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'preferences.php'; $preferences = new \Components\Tools\Tables\Preferences($database); $preferences->loadByUser($result->get('uidNumber')); if (!$preferences || !$preferences->id) { include_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'sessionclass.php'; $scls = new \Components\Tools\Tables\SessionClass($this->database); $default = $scls->find('one', array('alias' => 'default')); $preferences->user_id = $result->get('uidNumber'); $preferences->class_id = $default->id; $preferences->jobs = $default->jobs ? $default->jobs : 3; $preferences->store(); } $remain = $preferences->jobs - $jobs; //can we open another session if ($remain <= 0) { throw new Exception(Lang::txt('You are using all (%s) your available job slots.', $jobs), 401); } // Get plugins Plugin::import('mw', $app->name); // Trigger any events that need to be called before session invoke Event::trigger('mw.onBeforeSessionInvoke', array($app->toolname, $app->version)); // We've passed all checks so let's actually start the session $status = \Components\Tools\Helpers\Utils::middleware("start user="******" ip=" . $app->ip . " app=" . $app->name . " version=" . $app->version, $output); //make sure we got a valid session back from the middleware if (!isset($output->session)) { throw new Exception(Lang::txt('There was a issue while trying to start the tool session. Please try again later.'), 500); } //set session output $app->sess = $output->session; // Trigger any events that need to be called after session invoke Event::trigger('mw.onAfterSessionInvoke', array($app->toolname, $app->version)); // Get a count of the number of sessions of this specific tool $appcount = $ms->getCount($result->get('username'), $app->name); // Do we have more than one session of this tool? if ($appcount > 1) { // We do, so let's append a timestamp $app->caption .= ' (' . Date::format("g:i a") . ')'; } // Save the changed caption $ms->load($app->sess); $ms->sessname = $app->caption; if (!$ms->store()) { throw new Exception(Lang::txt('There was a issue while trying to start the tool session. Please try again later.'), 500); } //add tool title to output //add session title to ouput $output->tool = $app->title; $output->session_title = $app->caption; $output->owner = 1; $output->readonly = 0; //return result if ($status) { $this->send($output); } }