393 lines
13 KiB
PHP
393 lines
13 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public License
|
||
|
* as published by the Free Software Foundation; under version 2
|
||
|
* of the License (non-upgradable).
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*
|
||
|
* Copyright (c) 2015-2019 (original work) Open Assessment Technologies SA;
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
namespace oat\taoClientDiagnostic\controller;
|
||
|
|
||
|
use oat\tao\model\mvc\DefaultUrlService;
|
||
|
use oat\taoClientDiagnostic\exception\StorageException;
|
||
|
use oat\taoClientDiagnostic\model\authorization\Authorization;
|
||
|
use oat\taoClientDiagnostic\model\CompatibilityChecker as CompatibilityCheckerModel;
|
||
|
use oat\taoClientDiagnostic\model\diagnostic\DiagnosticServiceInterface;
|
||
|
use oat\taoClientDiagnostic\model\schoolName\SchoolNameService;
|
||
|
use oat\taoClientDiagnostic\model\storage\Storage;
|
||
|
use Sinergi\BrowserDetector\Browser;
|
||
|
use Sinergi\BrowserDetector\Os;
|
||
|
|
||
|
/**
|
||
|
* Class CompatibilityChecker
|
||
|
* @package oat\taoClientDiagnostic\controller
|
||
|
*/
|
||
|
class CompatibilityChecker extends \tao_actions_CommonModule
|
||
|
{
|
||
|
|
||
|
const COOKIE_ID = 'compatibility_checker_id';
|
||
|
|
||
|
/**
|
||
|
* If logged in, display index view with config data
|
||
|
* If not, forward to login
|
||
|
*/
|
||
|
public function index()
|
||
|
{
|
||
|
$authorizationService = $this->getServiceLocator()->get(Authorization::SERVICE_ID);
|
||
|
if ($authorizationService->isAuthorized()) {
|
||
|
$config = $this->loadConfig();
|
||
|
|
||
|
if (!empty($config['diagnostic']['pageTitle'])) {
|
||
|
$this->setData('title', $config['diagnostic']['pageTitle']);
|
||
|
}
|
||
|
|
||
|
$this->setData('client_config_url', $this->getClientConfigUrl());
|
||
|
$this->setData('content-config', $config);
|
||
|
$this->setData('logout', $this->getServiceLocator()->get(DefaultUrlService::SERVICE_ID)->getLogoutUrl());
|
||
|
$this->setData('content-controller', 'taoClientDiagnostic/controller/CompatibilityChecker/diagnostics');
|
||
|
$this->setData('content-template', 'CompatibilityChecker' . DIRECTORY_SEPARATOR . 'diagnostics.tpl');
|
||
|
$this->setView('index.tpl');
|
||
|
} else {
|
||
|
$this->redirect($authorizationService->getAuthorizationUrl(_url('index')));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Render browser detection view
|
||
|
*/
|
||
|
public function whichBrowser()
|
||
|
{
|
||
|
$result = [
|
||
|
'browser' => $this->getBrowserDetector()->getName(),
|
||
|
'browserVersion' => $this->getBrowserDetector()->getVersion(),
|
||
|
'os' => $this->getOsDetector()->getName(),
|
||
|
'osVersion' => $this->getOsDetector()->getVersion(),
|
||
|
'isMobile' => $this->getOsDetector()->isMobile(),
|
||
|
];
|
||
|
$this->returnJson($result);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if requester is compatible (os+browser)
|
||
|
* Register compatibility
|
||
|
* return json message
|
||
|
*/
|
||
|
public function check()
|
||
|
{
|
||
|
try {
|
||
|
$data = $this->getData(true);
|
||
|
$id = $this->getId();
|
||
|
|
||
|
$checker = $this->getServiceLocator()->get(CompatibilityCheckerModel::SERVICE_ID);
|
||
|
$isCompatible = (int)$checker->isCompatibleConfig();
|
||
|
$data['compatible'] = $isCompatible;
|
||
|
|
||
|
try {
|
||
|
$storageService = $this->getServiceLocator()->get(Storage::SERVICE_ID);
|
||
|
$storageService->store($id, $data);
|
||
|
} catch (StorageException $e) {
|
||
|
$this->logInfo($e->getMessage());
|
||
|
}
|
||
|
|
||
|
$compatibilityMessage = [
|
||
|
//Not compatible
|
||
|
CompatibilityCheckerModel::COMPATIBILITY_NONE => [
|
||
|
'success' => true,
|
||
|
'type' => 'error',
|
||
|
'message' => __('Your system requires a compatibility update, please contact your system administrator.')
|
||
|
],
|
||
|
//Compatible
|
||
|
CompatibilityCheckerModel::COMPATIBILITY_COMPATIBLE => [
|
||
|
'success' => true,
|
||
|
'type' => 'success',
|
||
|
'message' => __('This browser is compatible but its support may end soon.')
|
||
|
],
|
||
|
//Not tested
|
||
|
CompatibilityCheckerModel::COMPATIBILITY_NOT_TESTED => [
|
||
|
'success' => true,
|
||
|
'type' => 'warning',
|
||
|
'message' => __('This browser is not tested.')
|
||
|
],
|
||
|
//Fully supported
|
||
|
CompatibilityCheckerModel::COMPATIBILITY_SUPPORTED => [
|
||
|
'success' => true,
|
||
|
'type' => 'success',
|
||
|
'message' => __('This browser is supported.')
|
||
|
],
|
||
|
//Not supported
|
||
|
CompatibilityCheckerModel::COMPATIBILITY_NOT_SUPPORTED => [
|
||
|
'success' => true,
|
||
|
'type' => 'warning',
|
||
|
'message' => __('This browser is not supported.')
|
||
|
],
|
||
|
];
|
||
|
|
||
|
$this->returnJson($compatibilityMessage[$isCompatible]);
|
||
|
|
||
|
} catch (\common_exception_MissingParameter $e) {
|
||
|
$this->returnJson(array('success' => false, 'type' => 'error', 'message' => $e->getUserMessage()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Action is used to check upload speed from client side.
|
||
|
*/
|
||
|
public function upload()
|
||
|
{
|
||
|
try {
|
||
|
if ($this->getRequestMethod() !== \Request::HTTP_POST) {
|
||
|
throw new \common_exception_NotImplemented('Only post method is accepted.');
|
||
|
}
|
||
|
if (!isset($_POST['upload']) || !is_string($_POST['upload'])) {
|
||
|
throw new \common_exception_InconsistentData("'upload' POST variable is missed.");
|
||
|
}
|
||
|
$size = mb_strlen($_POST['upload'], '8bit');
|
||
|
$result = ['success' => true, 'size' => $size];
|
||
|
} catch (\common_exception_NotImplemented $e) {
|
||
|
$result = ['success' => false, 'error' => $e->getMessage()];
|
||
|
$this->logWarning($e->getMessage());
|
||
|
} catch (\common_exception_InconsistentData $e) {
|
||
|
$result = ['success' => false, 'error' => $e->getMessage()];
|
||
|
$this->logWarning($e->getMessage());
|
||
|
} catch (\Exception $e) {
|
||
|
$result = ['success' => false, 'type' => 'error', 'message' => 'Please contact administrator'];
|
||
|
$this->logWarning($e->getMessage());
|
||
|
}
|
||
|
$this->returnJson($result);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register data from the front end
|
||
|
*/
|
||
|
public function storeData()
|
||
|
{
|
||
|
$data = $this->getData();
|
||
|
$id = $this->getId();
|
||
|
|
||
|
try {
|
||
|
$storageService = $this->getServiceLocator()->get(Storage::SERVICE_ID);
|
||
|
$storageService->store($id, $data);
|
||
|
$this->returnJson(array('success' => true, 'type' => 'success'));
|
||
|
} catch (StorageException $e) {
|
||
|
$this->logInfo($e->getMessage());
|
||
|
$this->returnJson(array('success' => false, 'type' => 'error'));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve a school name
|
||
|
*/
|
||
|
public function schoolName()
|
||
|
{
|
||
|
// simple counter measure to slow down brute force attack
|
||
|
sleep(1);
|
||
|
|
||
|
$data = $this->getParameters();
|
||
|
|
||
|
$required = ['school_number', 'school_pin'];
|
||
|
|
||
|
$response = [];
|
||
|
$success = true;
|
||
|
|
||
|
foreach($required as $fieldName) {
|
||
|
if (!isset($data[$fieldName])) {
|
||
|
$success = false;
|
||
|
$response['errorCode'] = 400;
|
||
|
$response['errorMessage'] = __('Missing field %s', $fieldName);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($success) {
|
||
|
try {
|
||
|
$schoolNameProvider = $this->getServiceLocator()->get(SchoolNameService::SERVICE_ID);
|
||
|
$response['data'] = $schoolNameProvider->getSchoolName($data['school_number'], $data['school_pin']);
|
||
|
} catch(\Exception $e) {
|
||
|
$success = false;
|
||
|
$response['errorCode'] = 404;
|
||
|
$response['errorMessage'] = __('Cannot retrieve the school name. Please verify your input');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$response['success'] = $success;
|
||
|
$this->returnJson($response);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Fetch POST data
|
||
|
* Get login by cookie
|
||
|
* Get Ip
|
||
|
* If check parameters is true, check mandatory parameters
|
||
|
*
|
||
|
* @param bool $check
|
||
|
* @return array
|
||
|
* @throws \common_exception_MissingParameter
|
||
|
*/
|
||
|
protected function getData($check = false)
|
||
|
{
|
||
|
$data = $this->getParameters();
|
||
|
|
||
|
if ($this->hasRequestParameter('type')) {
|
||
|
$type = $this->getRequestParameter('type');
|
||
|
unset($data['type']);
|
||
|
|
||
|
if ($type !== 'custom_input') {
|
||
|
foreach ($data as $key => $value) {
|
||
|
$data[$type . '_' . $key] = $value;
|
||
|
unset($data[$key]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$data = $this->mapData($data);
|
||
|
|
||
|
if ($this->hasRequestParameter('school_name')) {
|
||
|
$data[Storage::DIAGNOSTIC_SCHOOL_NAME] = \tao_helpers_Display::sanitizeXssHtml(trim($this->getRequestParameter('school_name')));
|
||
|
}
|
||
|
|
||
|
if ($this->hasRequestParameter('school_id')) {
|
||
|
$data[Storage::DIAGNOSTIC_SCHOOL_ID] = \tao_helpers_Display::sanitizeXssHtml(trim($this->getRequestParameter('school_id')));
|
||
|
}
|
||
|
|
||
|
if ($this->hasRequestParameter('workstation')) {
|
||
|
$data[Storage::DIAGNOSTIC_WORKSTATION] = \tao_helpers_Display::sanitizeXssHtml(trim($this->getRequestParameter('workstation')));
|
||
|
}
|
||
|
|
||
|
if ($this->hasRequestParameter('school_number')) {
|
||
|
$data[Storage::DIAGNOSTIC_SCHOOL_NUMBER] = \tao_helpers_Display::sanitizeXssHtml(trim($this->getRequestParameter('school_number')));
|
||
|
}
|
||
|
|
||
|
if ($check) {
|
||
|
if (!$this->hasRequestParameter('os')) {
|
||
|
throw new \common_exception_MissingParameter('os');
|
||
|
}
|
||
|
if (!$this->hasRequestParameter('osVersion')) {
|
||
|
throw new \common_exception_MissingParameter('osVersion');
|
||
|
}
|
||
|
if (!$this->hasRequestParameter('browser')) {
|
||
|
throw new \common_exception_MissingParameter('browser');
|
||
|
}
|
||
|
if (!$this->hasRequestParameter('browserVersion')) {
|
||
|
throw new \common_exception_MissingParameter('browserVersion');
|
||
|
}
|
||
|
$data['osVersion'] = preg_replace('/[^\w\.]/', '', $data['osVersion']);
|
||
|
$data['browserVersion'] = preg_replace('/[^\w\.]/', '', $data['browserVersion']);
|
||
|
}
|
||
|
|
||
|
if (isset($_COOKIE['login'])) {
|
||
|
$data['login'] = $_COOKIE['login'];
|
||
|
} else {
|
||
|
$data['login'] = 'Anonymous';
|
||
|
}
|
||
|
|
||
|
$user = \common_session_SessionManager::getSession()->getUser();
|
||
|
if ($user && $user->getIdentifier()) {
|
||
|
$data['user_id'] = $user->getIdentifier();
|
||
|
}
|
||
|
|
||
|
$data['version'] = $this->getServiceLocator()->get(\common_ext_ExtensionsManager::SERVICE_ID)->getExtensionById('taoClientDiagnostic')->getVersion();
|
||
|
|
||
|
$data['ip'] = (!empty($_SERVER['HTTP_X_REAL_IP'])) ? $_SERVER['HTTP_X_REAL_IP'] : ((!empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : 'unknown');
|
||
|
return $data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get current http parameters
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
protected function getParameters()
|
||
|
{
|
||
|
return $this->getRequestParameters();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get cookie id OR create it if doesnt exist
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function getId()
|
||
|
{
|
||
|
if (! isset($_COOKIE[self::COOKIE_ID])) {
|
||
|
$id = uniqid();
|
||
|
setcookie(self::COOKIE_ID, $id);
|
||
|
} else {
|
||
|
$id = $_COOKIE[self::COOKIE_ID];
|
||
|
}
|
||
|
return $id;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Delete cookie id
|
||
|
*/
|
||
|
public function deleteId()
|
||
|
{
|
||
|
setcookie(self::COOKIE_ID, null);
|
||
|
$this->returnJson(array('success' => true, 'type' => 'success'));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get config parameters for compatibility check
|
||
|
*
|
||
|
* @return mixed
|
||
|
*/
|
||
|
protected function loadConfig()
|
||
|
{
|
||
|
/** @var DiagnosticServiceInterface $service */
|
||
|
$service = $this->getServiceLocator()->get(DiagnosticServiceInterface::SERVICE_ID);
|
||
|
$config = $service->getDiagnosticJsConfig();
|
||
|
$config['controller'] = 'CompatibilityChecker';
|
||
|
return $config;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Map custom input data from the 'customInput' configuration.
|
||
|
*
|
||
|
* @param array $data
|
||
|
* @return array
|
||
|
*/
|
||
|
protected function mapData(array $data) {
|
||
|
$config = $this->loadConfig();
|
||
|
|
||
|
foreach ($data as $k => $d) {
|
||
|
if (!empty($config['diagnostic']['customInput'][$k])) {
|
||
|
$data[$config['diagnostic']['customInput'][$k]] = $d;
|
||
|
unset($data[$k]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $data;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the browser detector
|
||
|
*
|
||
|
* @return Browser
|
||
|
*/
|
||
|
protected function getBrowserDetector()
|
||
|
{
|
||
|
return new Browser();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the operating system detector
|
||
|
*
|
||
|
* @return Os
|
||
|
*/
|
||
|
protected function getOsDetector()
|
||
|
{
|
||
|
return new Os();
|
||
|
}
|
||
|
}
|