This commit is contained in:
Juan Ferrer Toribio 2016-08-22 12:41:05 +02:00
parent 1e660bc451
commit a7ed0a662a
21 changed files with 397 additions and 392 deletions

View File

@ -8,7 +8,7 @@ set_include_path
.PATH_SEPARATOR.__DIR__ .PATH_SEPARATOR.__DIR__
); );
const _DEVELOPER_MODE = TRUE; const _DEBUG_MODE = TRUE;
const _CONFIG_DIR = '/home/juan/.config'; const _CONFIG_DIR = '/home/juan/.config';
const _LOG_DIR = '/tmp'; const _LOG_DIR = '/tmp';
const _DATA_DIR = '/tmp'; const _DATA_DIR = '/tmp';

View File

@ -62,7 +62,7 @@ Db.Conn.implement
else if (guest) else if (guest)
var params = {'guest': true}; var params = {'guest': true};
var request = new Vn.JsonRequest ('login'); var request = new Vn.JsonRequest ('core/login');
request.send (params, request.send (params,
this._onOpen.bind (this, callback)); this._onOpen.bind (this, callback));
} }
@ -94,7 +94,7 @@ Db.Conn.implement
{ {
this.signalEmit ('loading-changed', true); this.signalEmit ('loading-changed', true);
var request = new Vn.JsonRequest ('logout'); var request = new Vn.JsonRequest ('core/logout');
request.send (null, request.send (null,
this._onClose.bind (this, callback)); this._onClose.bind (this, callback));
} }
@ -127,7 +127,7 @@ Db.Conn.implement
if (this._requestsCount === 1) if (this._requestsCount === 1)
this.signalEmit ('loading-changed', true); this.signalEmit ('loading-changed', true);
var request = new Vn.JsonRequest ('query'); var request = new Vn.JsonRequest ('core/query');
request.send ({'sql': sql}, request.send ({'sql': sql},
this._onExec.bind (this, callback)); this._onExec.bind (this, callback));
} }

View File

@ -117,23 +117,20 @@ Vn.App = new Class
,_onConnError: function (conn, error) ,_onConnError: function (conn, error)
{ {
if (error instanceof Vn.Error) if (error instanceof Vn.JsonException)
switch (error.code) switch (error.exception)
{ {
case 'badLogin': case 'Vn\\Web\\BadLoginException':
Htk.Toast.showError (_('Invalid login')); Htk.Toast.showError (_('Invalid login'));
this._logout (); this._logout ();
break; break;
case 'sessionExpired': case 'Vn\\Web\\SessionExpiredException':
Htk.Toast.showError (_('You\'ve been too idle')); Htk.Toast.showError (_('You\'ve been too idle'));
this._logout (); this._logout ();
break; break;
case 'newVersion': case 'Vn\\Web\\OutdatedVersionException':
this._newVersion (error); this._newVersion (error);
break; break;
case 'internalError':
Htk.Toast.showError (_('There was an internal error'));
break;
default: default:
Htk.Toast.showError (error.message); Htk.Toast.showError (error.message);
} }
@ -152,29 +149,13 @@ Vn.App = new Class
,_newVersion: function (error) ,_newVersion: function (error)
{ {
if (this.newVersionBlock || this.skipVersion) if (this.skipVersion)
return; return;
this.newVersionBlock = true;
var reload; this.skipVersion = true;
var message = _('New version available') +"\n\n"+ error.message;
if (error.code == 'criticalVersion') if (confirm (_('New version available')))
{
alert (message)
reload = true;
}
else
{
reload = confirm (message);
this.skipVersion = true;
}
if (reload)
location.reload (); location.reload ();
this.newVersionBlock = false;
} }
,_notifyError: function (error) ,_notifyError: function (error)

View File

@ -68,7 +68,7 @@ Vn.Module = new Class
var klassName = this.toCamelCase (this.moduleName); var klassName = this.toCamelCase (this.moduleName);
try { try {
this.klass = eval (klassName); this.klass = Vn[klassName];
} }
catch (e) catch (e)
{ {
@ -85,7 +85,7 @@ Vn.Module = new Class
,toCamelCase: function (dashedName) ,toCamelCase: function (dashedName)
{ {
var camelCase = 'Vn.'+ dashedName.charAt (0).toUpperCase (); var camelCase = dashedName.charAt (0).toUpperCase ();
camelCase += dashedName.substr (1).replace (/\w\-\w/g, function (token) camelCase += dashedName.substr (1).replace (/\w\-\w/g, function (token)
{ {
return token.charAt (0) + token.charAt (2).toUpperCase (); return token.charAt (0) + token.charAt (2).toUpperCase ();

View File

@ -527,20 +527,10 @@ Vn.Builder = new Class
,_getMethod: function (value) ,_getMethod: function (value)
{ {
if (this.signalData) if (this.signalData)
var methodName = 'this.signalData.'+ value; var method = this.signalData[value];
else else
var methodName = value; var method = window[value];
var method;
try {
method = eval (methodName);
}
catch (e)
{
method = undefined;
}
if (method === undefined) if (method === undefined)
this._showError ('Function \'%s\' not found', value); this._showError ('Function \'%s\' not found', value);

View File

@ -1,11 +1,14 @@
/** /**
* This class stores the database errors. * This class stores the database errors.
**/ **/
Vn.Error = new Class Vn.JsonException = new Class
({ ({
domain: null exception: null
,code: null
,message: null ,message: null
,code: null
,file: null
,line: null
,trace: null
,initialize: function (domain, code, message) ,initialize: function (domain, code, message)
{ {

View File

@ -21,7 +21,7 @@ Vn.JsonRequest = new Class
,send: function (params, callback) ,send: function (params, callback)
{ {
var url = 'rest.php?method='+ encodeURIComponent (this._methodName); var url = 'json.php?method='+ encodeURIComponent (this._methodName);
this.sendWithUrl (params, callback, 'post', url); this.sendWithUrl (params, callback, 'post', url);
} }
@ -30,31 +30,38 @@ Vn.JsonRequest = new Class
if (request.readyState !== 4) if (request.readyState !== 4)
return; return;
var jsData = null; var data = null;
var error = null; var error = null;
try { try {
if (request.status !== 200)
throw new Error (request.statusText);
var json = JSON.parse (request.responseText); var json = JSON.parse (request.responseText);
var jsData = json.data; var jsData = json.data;
var jsError = json.error; var jsWarns = json.warnings;
if (jsError) if (request.status == 200)
throw new Vn.Error ( {
jsError.domain, data = jsData;
jsError.code, }
jsError.message); else
{
var ex = new Vn.JsonException ();
ex.exception = jsData.exception;
ex.message = jsData.message;
ex.code = jsData.code;
ex.file = jsData.file;
ex.line = jsData.line;
ex.trace = jsData.trace;
throw ex;
}
} }
catch (e) catch (e)
{ {
jsData = null; data = null;
error = e; error = e;
} }
if (callback) if (callback)
callback (this, jsData, error); callback (this, data, error);
} }
,sendForm: function (form, callback) ,sendForm: function (form, callback)

View File

@ -44,7 +44,7 @@ Vn.Locale =
if (request.status == 200) if (request.status == 200)
{ {
try { try {
this.add (eval ('('+ request.responseText +')')); this.add (JSON.parse (request.responseText));
success = true; success = true;
} }
catch (e) { catch (e) {

View File

@ -6,7 +6,6 @@ Vn.includeLib ('vn',
,'cookie' ,'cookie'
,'date' ,'date'
,'value' ,'value'
,'error'
,'url' ,'url'
,'mutators' ,'mutators'
,'object' ,'object'
@ -16,6 +15,7 @@ Vn.includeLib ('vn',
,'hash-param' ,'hash-param'
,'node' ,'node'
,'builder' ,'builder'
,'json-exception'
,'json-request' ,'json-request'
]); ]);

9
json.php Executable file
View File

@ -0,0 +1,9 @@
<?php
require_once ('vn/hedera/hedera.php');
require_once ('vn/web/json-app.php');
$restApp = new Vn\Web\JsonApp (Vn\Hedera\APP_NAME, 'rest');
$restApp->run ();
?>

View File

@ -1,11 +1,12 @@
<?php <?php
require_once ('vn/web/json-request.php'); require_once ('vn/lib/method.php');
require_once (__DIR__.'/tpv.php');
/** /**
* Gets transaction confirmations from the IMAP mailbox. * Gets transaction confirmations from the IMAP mailbox.
**/ **/
class TpvConfirmMail extends Vn\Web\JsonRequest class TpvConfirmMail extends Vn\Lib\Method
{ {
function run () function run ()
{ {
@ -50,7 +51,7 @@ class TpvConfirmMail extends Vn\Web\JsonRequest
// Confirms the transaction // Confirms the transaction
try { try {
$success = $this->confirm ($params, $db); $success = Tpv::confirm ($db, $params);
} }
catch (\Exception $e) catch (\Exception $e)
{ {
@ -64,9 +65,7 @@ class TpvConfirmMail extends Vn\Web\JsonRequest
else else
$folder = $imapConf['error_folder']; $folder = $imapConf['error_folder'];
$folder = sprintf ('INBOX.%s', $folder); if (!imap_mail_move ($imap, $msg, "INBOX.$folder"))
if (!imap_mail_move ($imap, $msg, $folder))
trigger_error (imap_last_error (), E_USER_WARNING); trigger_error (imap_last_error (), E_USER_WARNING);
} }
@ -100,10 +99,7 @@ class TpvConfirmMail extends Vn\Web\JsonRequest
} }
} }
return [ echo "TPV: $count mails processed, $deleted mails deleted";
'processed' => $count,
'deleted' => $deleted
];
} }
} }

View File

@ -1,16 +1,16 @@
<?php <?php
require_once ('vn/web/json-request.php'); require_once ('vn/web/json-request.php');
require_once (__DIR__.'/tpv.php');
/** /**
* Gets transaction confirmation from HTTP POST. * Gets transaction confirmation from HTTP POST.
**/ **/
class TpvConfirmPost extends Vn\Web\JsonRequest class TpvConfirmPost extends Vn\Web\HttpRequest
{ {
function run () function run ()
{ {
$this->confirm ($_POST); Tpv::confirm ($db, $_POST);
return TRUE;
} }
} }

View File

@ -2,6 +2,7 @@
require_once ('vn/web/http-request.php'); require_once ('vn/web/http-request.php');
require_once ('vn/web/util.php'); require_once ('vn/web/util.php');
require_once (__DIR__.'/tpv.php');
/** /**
* Gets transaction confirmation from SOAP service. * Gets transaction confirmation from SOAP service.
@ -34,13 +35,13 @@ function procesaNotificacionSIS ($XML)
try { try {
$xml = new SimpleXMLElement ($requestString); $xml = new SimpleXMLElement ($requestString);
$request = (array) $xml->{'Request'}; $params = (array) $xml->{'Request'};
if (!(isset ($request['Ds_Amount']) if (!(isset ($params['Ds_Amount'])
&& isset ($request['Ds_Order']) && isset ($params['Ds_Order'])
&& isset ($request['Ds_MerchantCode']) && isset ($params['Ds_MerchantCode'])
&& isset ($request['Ds_Currency']) && isset ($params['Ds_Currency'])
&& isset ($request['Ds_Response']))) && isset ($params['Ds_Response'])))
throw new Exception ('Missing required parameters'); throw new Exception ('Missing required parameters');
// Checks the signature // Checks the signature
@ -51,7 +52,7 @@ function procesaNotificacionSIS ($XML)
$key = $db->getValue ( $key = $db->getValue (
'SELECT secret_key FROM tpv_merchant WHERE id = #' 'SELECT secret_key FROM tpv_merchant WHERE id = #'
,[$request['Ds_MerchantCode']] ,[$params['Ds_MerchantCode']]
); );
if (sha1 ($shaString.$key) != $xml->{'Signature'}) if (sha1 ($shaString.$key) != $xml->{'Signature'})
@ -59,7 +60,7 @@ function procesaNotificacionSIS ($XML)
// Confirms the transaction // Confirms the transaction
$tpvConfirmSoap->confirm ($request); Tpv::confirm ($db, $params);
} }
catch (Exception $e) catch (Exception $e)
{ {

View File

@ -12,23 +12,25 @@ use Vn\Db\Conn;
/** /**
* Thrown when user credentials could not be fetched. * Thrown when user credentials could not be fetched.
**/ **/
class SessionExpiredException extends \Exception {} class SessionExpiredException extends Lib\UserException {}
/** /**
* Thrown when user credentials are invalid. * Thrown when user credentials are invalid.
**/ **/
class BadLoginException extends \Exception {} class BadLoginException extends Lib\UserException {}
/** /**
* Thrown when client version is outdated. * Thrown when client version is outdated.
**/ **/
class OutdatedVersionException extends \Exception {} class OutdatedVersionException extends Lib\UserException {}
/** /**
* Main class for web applications. * Main class for web applications.
**/ **/
abstract class App extends Lib\App abstract class App extends Lib\App
{ {
protected $conn = NULL;
/** /**
* Starts the user session. * Starts the user session.
**/ **/
@ -36,7 +38,8 @@ abstract class App extends Lib\App
{ {
if ($this->isHttps ()) if ($this->isHttps ())
ini_set ('session.cookie_secure', TRUE); ini_set ('session.cookie_secure', TRUE);
ini_set ('session.hash_function', 'sha512');
session_start (); session_start ();
// Setting the locale // Setting the locale
@ -124,7 +127,7 @@ abstract class App extends Lib\App
function getVersion () function getVersion ()
{ {
return (int) strftime ('%G%m%d%H%M%S', return (int) strftime ('%G%m%d%H%M%S',
filectime ($_SERVER['SCRIPT_FILENAME'])); filectime (__FILE__ /* $_SERVER['SCRIPT_FILENAME'] */));
} }
/** /**
@ -145,147 +148,6 @@ abstract class App extends Lib\App
else else
return parent::getConfigFile (); return parent::getConfigFile ();
} }
/**
* Tries to retrieve user credentials from many sources such as POST,
* SESSION or COOKIES. If $_POST['remember'] is defined the user credentials
* are saved on the client brownser for future logins, cookies names are
* 'vn_user' for the user name and 'vn_pass' for user password, the
* password is encoded using base64_encode() function and should be decoded
* using base64_decode().
**/
function login ()
{
if ($this->conn)
return $this->conn;
$user = NULL;
$password = NULL;
$rememberUser = TRUE;
$rememberPass = FALSE;
$credentialsChanged = TRUE;
$wasLoged = isset ($_SESSION['user']);
if (isset ($_POST['guest']))
{
$sysConn = $this->getSysConn ();
$row = $sysConn->getRow (
'SELECT guest_user, guest_pass FROM config');
if ($row)
{
$user = $row['guest_user'];
$password = base64_decode ($row['guest_pass']);
$rememberUser = FALSE;
}
}
elseif (isset ($_POST['user']) && isset ($_POST['password']))
{
$user = $_POST['user'];
$password = $_POST['password'];
if (isset ($_POST['remember']) && $_POST['remember'])
$rememberPass = TRUE;
}
elseif (isset ($_SESSION['user']))
{
$user = $_SESSION['user'];
$password = $_SESSION['password'];
$credentialsChanged = FALSE;
}
elseif (isset ($_COOKIE['vn_user']) && isset ($_COOKIE['vn_pass']))
{
$user = $_COOKIE['vn_user'];
$password = base64_decode ($_COOKIE['vn_pass']);
$rememberPass = TRUE;
}
if (!isset ($user))
throw new SessionExpiredException ();
try {
$db = $this->createConnection ($user, $password);
$db->query ('CALL user_session_start (#)', [session_id ()]);
$this->conn = $db;
if ($rememberUser)
{
$cookieLife = time () + 7 * 86400; // 7 Days
setcookie ('vn_user', $user, $cookieLife);
if ($rememberPass)
setcookie ('vn_pass',
base64_encode ($password), $cookieLife);
}
$_SESSION['user'] = $user;
$_SESSION['password'] = $password;
}
catch (\Exception $e)
{
$this->conn = NULL;
throw new BadLoginException ();
}
// Registering the user access
if (!$wasLoged)
unset ($_SESSION['visitUser']);
if (isset ($_SESSION['access'])
&& !isset ($_SESSION['visitUser']))
{
$sysConn = $this->getSysConn ();
$_SESSION['visitUser'] = $sysConn->getValue (
'CALL visit_user_new (#, #, #)',
[
$_SESSION['access']
,nullIf ($_SESSION, 'visitUser')
,session_id ()
]
);
if (!isset ($_SESSION['visitUnknown']))
$_SESSION['visitUnknown'] = $_SESSION['visitUser'];
}
return $db;
}
/**
* Cleans the last saved used credentials.
**/
function logout ()
{
$_SESSION['visitUser'] = nullIf ($_SESSION, 'visitUnknown');
setcookie ('vn_pass', '', -1);
unset ($_COOKIE['vn_pass']);
unset ($_SESSION['user']);
unset ($_SESSION['password']);
if ($this->conn)
{
$this->conn->query (
'DELETE FROM user_session_view '
.'WHERE connection_id = CONNECTION_ID()'
);
$this->conn->close ();
$this->conn = NULL;
}
}
/**
* Deinitializes the Application. When init method is called, this
* function is called automatically at the end of the script .
**/
function deinit ()
{
if ($this->conn)
$this->conn->query ('CALL user_session_end ()');
parent::deinit ();
}
} }
?> ?>

View File

@ -98,7 +98,7 @@ class HtmlApp extends App
function printHeader () function printHeader ()
{ {
header ('Content-Type: text/html; charset=UTF-8'); header ('Content-Type: text/html; charset=UTF-8');
header ("Content-Security-Policy: default-src 'self'"); header ("Content-Security-Policy: default-src 'self'; img-src *");
} }
function globalErrorHandler () function globalErrorHandler ()

View File

@ -5,38 +5,8 @@ namespace Vn\Web;
require_once (__DIR__.'/rest-app.php'); require_once (__DIR__.'/rest-app.php');
/** /**
* Base class for rest services. * Base class for REST services.
**/ **/
class HttpRequest extends \Vn\Lib\Method abstract class HttpRequest extends \Vn\Lib\Method {}
{
function listen ()
{
try {
$this->run ();
}
catch (SessionExpiredException $e)
{
$this->httpError (403);
}
catch (BadLoginException $e)
{
$this->httpError (401);
}
catch (Exception $e)
{
$this->httpError (400);
}
}
function httpError ($code)
{
}
function setError ($message, $code)
{
http_response_code (400);
}
}
?> ?>

126
vn/web/json-app.php Normal file
View File

@ -0,0 +1,126 @@
<?php
namespace Vn\Web;
require_once (__DIR__.'/rest-app.php');
require_once (__DIR__.'/json-reply.php');
use Vn\Lib;
/**
* Base class for JSON application.
**/
class JsonApp extends RestApp
{
private $warnings = NULL;
function run ()
{
ini_set ('display_errors', FALSE);
set_error_handler ([$this, 'errorHandler'], E_ALL);
set_exception_handler ([$this, 'exceptionHandler']);
$this->init ();
$this->startSession ();
// Checks the client version
if (!empty ($_COOKIE['vn_version']))
$clientVersion = (int) $_COOKIE['vn_version'];
if (isset ($clientVersion)
&& $clientVersion < $this->getVersion ())
throw new OutdatedVersionException ();
$method = $this->loadMethod ($_REQUEST['method']);
$json = $method->run ();
$this->replyJson ($json);
}
function replyJson ($jsonData)
{
$reply = new JsonReply ();
$reply->data = $jsonData;
$reply->warnings = $this->warnings;
header ('Content-Type: application/json; charset=UTF-8');
echo json_encode ($reply);
}
function errorHandler ($errno, $message, $file, $line, $context)
{
$eUserWarn =
E_USER_NOTICE
| E_USER_WARNING
| E_USER_DEPRECATED;
$eCoreWarn =
E_NOTICE
| E_WARNING
| E_DEPRECATED;
$eWarn = $eUserWarn | $eCoreWarn;
$eUser = $eUserWarn | E_USER_ERROR;
$json = new JsonException ();
if (_DEBUG_MODE || $errno & $eUser)
$json->message = $message;
else
$json->message = 'Something went wrong';
if (_DEBUG_MODE)
{
$json->code = $errno;
$json->file = $file;
$json->line = $line;
}
if ($errno & $eWarn)
{
if (!isset ($this->warnings))
$this->warnings = [];
$this->warnings[] = $json;
}
else
{
http_response_code (500);
$this->replyJson ($json);
exit ();
}
return !($errno & $eUser);
}
function exceptionHandler ($e)
{
$json = new JsonException ();
if (_DEBUG_MODE || $e instanceof Lib\UserException)
{
$json->exception = get_class ($e);
$json->message = $e->getMessage ();
}
else
{
$json->exception = 'Exception';
$json->message = 'Something went wrong';
}
if (_DEBUG_MODE)
{
$json->code = $e->getCode ();
$json->file = $e->getFile ();
$json->line = $e->getLine ();
$json->trace = $e->getTraceAsString ();
}
$this->statusFromException ($e);
$this->replyJson ($json);
if (!($e instanceof Lib\UserException))
throw $e;
}
}
?>

View File

@ -5,20 +5,18 @@ namespace Vn\Web;
/** /**
* Class used to store information about errors, warnings and info messages. * Class used to store information about errors, warnings and info messages.
* *
* @property string $domain The domain name * @property string $exception The exception name
* @property string $code The code of message
* @property string $message The message string * @property string $message The message string
* @property string $code The code of message
**/ **/
class JsonMessage class JsonException
{ {
var $code; var $exception = NULL;
var $message; var $message;
var $code = NULL;
function __construct ($code, $message) var $file = NULL;
{ var $line = NULL;
$this->code = $code; var $trace = NULL;
$this->message = $message;
}
} }
?> ?>

View File

@ -2,17 +2,18 @@
namespace Vn\Web; namespace Vn\Web;
require_once (__DIR__.'/json-exception.php');
/** /**
* Class used for replies. * Class used for replies.
* *
* @property Error $error The error object or %NULL if no error
* @property array $warnings Array with warning messages
* @property Object $data The returned data * @property Object $data The returned data
* @property array $warnings Array with warning messages
**/ **/
class JsonReply class JsonReply
{ {
var $warnings = NULL;
var $data = NULL; var $data = NULL;
var $warnings = NULL;
} }
?> ?>

View File

@ -2,82 +2,11 @@
namespace Vn\Web; namespace Vn\Web;
require_once (__DIR__.'/http-request.php'); require_once (__DIR__.'/json-app.php');
require_once (__DIR__.'/json-reply.php');
require_once (__DIR__.'/json-message.php');
/** /**
* Base class for rest services. * Base class for JSON services.
**/ **/
class JsonRequest extends HttpRequest abstract class JsonRequest extends \Vn\Lib\Method {}
{
function listen ()
{
try {
// Checks the client version
if (!empty ($_COOKIE['vn_version']))
$clientVersion = (int) $_COOKIE['vn_version'];
if (isset ($clientVersion)
&& $clientVersion < $this->getVersion ())
throw new Lib\UserException (s('Critical version available'), 'newVersion');
// Fetchs the result
$json = $this->run ();
$this->json ($json);
}
catch (SessionExpiredException $e)
{
$this->setError (s('The session has expired'), 'sessionExpired');
}
catch (BadLoginException $e)
{
$this->setError (s('Invalid login'), 'badLogin');
}
catch (Lib\UserException $e)
{
$this->setError ($e->getMessage (), $e->getCode ());
}
}
function json ($json)
{
$reply = new JsonReply ();
$reply->data = $json;
if ($this->warnings)
{
$reply->warnings = [];
foreach ($this->warnings as $warning)
$reply->warnings = $warning;
}
$this->replyJson ($reply);
}
function replyJson ($reply)
{
header ('Content-Type: application/json; charset=UTF-8');
echo json_encode ($reply);
}
function addWarning ($message, $code)
{
if (!isset ($this->reply->warnings))
$this->reply->warnings = [];
$this->warnings[] = new JsonMessage ($code, $message);
}
function setError ($message, $code)
{
http_response_code (400);
$reply = new JsonMessage ($code, $message);
$this->replyJson ($reply);
}
}
?> ?>

View File

@ -4,72 +4,204 @@ namespace Vn\Web;
require_once (__DIR__.'/app.php'); require_once (__DIR__.'/app.php');
use Vn\Lib;
/** /**
* Base class for rest services. * Base class for REST application.
**/ **/
class RestApp extends App class RestApp extends App
{ {
private $error = NULL;
private $warnings = NULL;
function run () function run ()
{ {
$this->reply = new JsonReply (); ini_set ('display_errors', _DEBUG_MODE);
set_error_handler ([$this, 'errorHandler'], E_ALL);
set_exception_handler ([$this, 'exceptionHandler']);
$this->init (); $this->init ();
$this->startSession (); $this->startSession ();
$method = $this->loadMethod ($_REQUEST['method']);
$method->run ();
}
/**
* Tries to retrieve user credentials from many sources such as POST,
* SESSION or COOKIES. If $_POST['remember'] is defined the user credentials
* are saved on the client brownser for future logins, cookies names are
* 'vn_user' for the user name and 'vn_pass' for user password, the
* password is encoded using base64_encode() function and should be decoded
* using base64_decode().
**/
function login ()
{
if ($this->conn)
return $this->conn;
$user = NULL;
$password = NULL;
$rememberUser = TRUE;
$rememberPass = FALSE;
$credentialsChanged = TRUE;
$wasLoged = isset ($_SESSION['user']);
if (isset ($_POST['guest']))
{
$sysConn = $this->getSysConn ();
$row = $sysConn->getRow (
'SELECT guest_user, guest_pass FROM config');
if ($row)
{
$user = $row['guest_user'];
$password = base64_decode ($row['guest_pass']);
$rememberUser = FALSE;
}
}
elseif (isset ($_POST['user']) && isset ($_POST['password']))
{
$user = $_POST['user'];
$password = $_POST['password'];
if (isset ($_POST['remember']) && $_POST['remember'])
$rememberPass = TRUE;
}
elseif (isset ($_SESSION['user']))
{
$user = $_SESSION['user'];
$password = $_SESSION['password'];
$credentialsChanged = FALSE;
}
elseif (isset ($_COOKIE['vn_user']) && isset ($_COOKIE['vn_pass']))
{
$user = $_COOKIE['vn_user'];
$password = base64_decode ($_COOKIE['vn_pass']);
$rememberPass = TRUE;
}
if (!isset ($user))
throw new SessionExpiredException ();
try { try {
// Checks the client version $db = $this->createConnection ($user, $password);
$db->query ('CALL user_session_start (#)', [session_id ()]);
$this->conn = $db;
if (!empty ($_COOKIE['vn_version'])) if ($rememberUser)
$clientVersion = (int) $_COOKIE['vn_version']; {
$cookieLife = time () + 7 * 86400; // 7 Days
setcookie ('vn_user', $user, $cookieLife);
if (isset ($clientVersion) if ($rememberPass)
&& $clientVersion < $this->getVersion ()) setcookie ('vn_pass',
throw new Lib\UserException (s('Critical version available'), 'newVersion'); base64_encode ($password), $cookieLife);
}
// Fetchs the result $_SESSION['user'] = $user;
$_SESSION['password'] = $password;
}
catch (\Exception $e)
{
$this->conn = NULL;
throw new BadLoginException ();
}
$method = $this->loadMethod ($_REQUEST['method']); // Registering the user access
$method->run ();
if (!$wasLoged)
unset ($_SESSION['visitUser']);
if (isset ($_SESSION['access'])
&& !isset ($_SESSION['visitUser']))
{
$sysConn = $this->getSysConn ();
$_SESSION['visitUser'] = $sysConn->getValue (
'CALL visit_user_new (#, #, #)',
[
$_SESSION['access']
,nullIf ($_SESSION, 'visitUser')
,session_id ()
]
);
if (!isset ($_SESSION['visitUnknown']))
$_SESSION['visitUnknown'] = $_SESSION['visitUser'];
}
return $db;
}
/**
* Cleans the last saved used credentials.
**/
function logout ()
{
$_SESSION['visitUser'] = nullIf ($_SESSION, 'visitUnknown');
setcookie ('vn_pass', '', -1);
unset ($_COOKIE['vn_pass']);
unset ($_SESSION['user']);
unset ($_SESSION['password']);
if ($this->conn)
{
$this->conn->query (
'DELETE FROM user_session_view '
.'WHERE connection_id = CONNECTION_ID()'
);
$this->conn->close ();
$this->conn = NULL;
}
}
/**
* Deinitializes the Application. When init method is called, this
* function is called automatically at the end of the script .
**/
function deinit ()
{
if ($this->conn)
$this->conn->query ('CALL user_session_end ()');
parent::deinit ();
}
function statusFromException ($e)
{
try {
throw $e;
} }
catch (SessionExpiredException $e) catch (SessionExpiredException $e)
{ { $status = 401; }
$this->setError (s('The session has expired'), 'sessionExpired');
}
catch (BadLoginException $e) catch (BadLoginException $e)
{ { $status = 401; }
$this->setError (s('Invalid login'), 'badLogin');
}
catch (Lib\UserException $e) catch (Lib\UserException $e)
{ { $status = 400; }
$this->setError ($e->getMessage (), $e->getCode ()); catch (\Exception $e)
} { $status = 500; }
http_response_code ($status);
} }
function errorHandler ($errno, $message, $file, $line, $context) function errorHandler ($errno, $message, $file, $line, $context)
{ {
switch ($errno) $eFlag =
{ E_USER_NOTICE
case E_USER_WARNING: | E_USER_WARNING
$this->addWarning ($message, $errno); | E_USER_DEPRECATED
break; | E_NOTICE
case E_WARNING: | E_WARNING
case E_CORE_WARNING: | E_DEPRECATED;
case E_COMPILE_WARNING:
$this->addWarning ('Something has gone wrong', 'internalWarning'); if (!($errno & $eFlag))
default: http_response_code (500);
return parent::errorHandler ($errno, $message, $file, $line, $context);
} return FALSE;
return TRUE;
} }
function globalErrorHandler () function exceptionHandler ($e)
{ {
$this->setError ('An internal error has occurred', 'internalError'); $this->statusFromException ($e);
exit (0); throw $e;
} }
} }