This commit is contained in:
Juan Ferrer Toribio 2016-09-24 00:47:34 +02:00
parent 5c159f3ceb
commit ee3e4cf041
31 changed files with 414 additions and 379 deletions

View File

@ -34,8 +34,8 @@ Vn.Catalog = new Class
this.$('items-model').setInfo ('a', 'Articles', 'vn2008', ['item_id']); this.$('items-model').setInfo ('a', 'Articles', 'vn2008', ['item_id']);
if (Vn.Cookie.check ('hedera_view')) if (localStorage.getItem ('hederaView'))
this.setView (Vn.Cookie.getInt ('hedera_view')); this.setView (parsetInt (localStorage.getItem ('hederaView')));
else else
this.setView (Vn.Catalog.View.GRID); this.setView (Vn.Catalog.View.GRID);
} }
@ -70,7 +70,7 @@ Vn.Catalog = new Class
var node = this.$('grid-view').getNode (); var node = this.$('grid-view').getNode ();
node.className = className; node.className = className;
Vn.Cookie.set ('hedera_view', this.view); localStorage.setItem ('hederaView', this.view);
} }
,onSwitchViewClick: function () ,onSwitchViewClick: function ()

View File

@ -26,93 +26,7 @@ Db.Conn = new Class ().extend
Db.Conn.implement Db.Conn.implement
({ ({
Extends: Vn.Object Extends: Vn.JsonConnection
,_connected: false
,_requestsCount: 0
/**
* Initilizes the connection object.
**/
,initialize: function ()
{
this.parent ();
}
/**
* Opens the connection to the database.
*
* @param {string} user The user name
* @param {String} password The user password
* @param {Boolean} remember Specifies if the user should be remembered
* @param {Function} openCallback The function to call when operation is done
**/
,open: function (user, pass, remember, callback, guest)
{
this.signalEmit ('loading-changed', true);
if (user != null)
{
var params = {
'user': user
,'password': pass
,'remember': remember
};
}
else if (guest)
var params = {'guest': true};
var request = new Vn.JsonRequest ('core/login');
request.send (params,
this._onOpen.bind (this, callback));
}
/*
* Called when open operation is done.
*/
,_onOpen: function (callback, request, json, error)
{
this._connected = json == true;
this.signalEmit ('loading-changed', false);
if (this._connected)
this.signalEmit ('openned');
if (error)
this.signalEmit ('error', error);
if (callback)
callback (this, this._connected, error);
}
/**
* Closes the connection to the database.
*
* @param {Function} callback The function to call when operation is done
**/
,close: function (callback)
{
this.signalEmit ('loading-changed', true);
var request = new Vn.JsonRequest ('core/logout');
request.send (null,
this._onClose.bind (this, callback));
}
/*
* Called when close operation is done.
*/
,_onClose: function (callback, request, json, error)
{
this._connected = false;
this.signalEmit ('loading-changed', false);
this.signalEmit ('closed');
if (error)
this.signalEmit ('error', error);
if (callback)
callback (this, json == true, error);
}
/** /**
* Runs a SQL query on the database. * Runs a SQL query on the database.
@ -122,13 +36,7 @@ Db.Conn.implement
**/ **/
,execSql: function (sql, callback) ,execSql: function (sql, callback)
{ {
this._requestsCount++; this.send ('core/query', {'sql': sql},
if (this._requestsCount === 1)
this.signalEmit ('loading-changed', true);
var request = new Vn.JsonRequest ('core/query');
request.send ({'sql': sql},
this._onExec.bind (this, callback)); this._onExec.bind (this, callback));
} }
@ -167,13 +75,8 @@ Db.Conn.implement
/* /*
* Called when a query is executed. * Called when a query is executed.
*/ */
,_onExec: function (callback, request, json, error) ,_onExec: function (callback, json, error)
{ {
this._requestsCount--;
if (this._requestsCount === 0)
this.signalEmit ('loading-changed', false);
if (json) if (json)
try { try {
if (json && json instanceof Array) if (json && json instanceof Array)

View File

@ -118,22 +118,29 @@ Vn.App = new Class
,_onConnError: function (conn, error) ,_onConnError: function (conn, error)
{ {
if (error instanceof Vn.JsonException) if (error instanceof Vn.JsonException)
switch (error.exception)
{ {
case 'Vn\\Web\\BadLoginException': var exception = error.exception
.replace (/\\/g, '.')
.replace (/Exception$/, '')
.replace (/^Vn\.Web\./, '');
switch (exception)
{
case 'BadLogin':
Htk.Toast.showError (_('Invalid login')); Htk.Toast.showError (_('Invalid login'));
this._logout (); this._logout ();
break; break;
case 'Vn\\Web\\SessionExpiredException': case 'SessionExpired':
Htk.Toast.showError (_('You\'ve been too idle')); Htk.Toast.showError (_('You\'ve been too idle'));
this._logout (); this._logout ();
break; break;
case 'Vn\\Web\\OutdatedVersionException': case 'OutdatedVersion':
this._newVersion (error); this._newVersion (error);
break; break;
default: default:
Htk.Toast.showError (error.message); Htk.Toast.showError (error.message);
} }
}
else else
{ {
console.error (error); console.error (error);
@ -168,9 +175,7 @@ Vn.App = new Class
,'message': error.message ,'message': error.message
,'stack': error.stack ,'stack': error.stack
}; };
this._conn.send ('core/log', params);
var request = new Vn.JsonRequest ('core/log');
request.send (params);
} }
,_freeLogin: function () ,_freeLogin: function ()

View File

@ -84,9 +84,9 @@ Vn.Gui = new Class
this.formParam = new Vn.HashParam ({key: 'form'}); this.formParam = new Vn.HashParam ({key: 'form'});
this.formParam.on ('changed', this._onFormChange, this); this.formParam.on ('changed', this._onFormChange, this);
if (!Vn.Cookie.check ('hedera_cookies')) if (!localStorage.getItem ('hederaCookies'))
{ {
Vn.Cookie.set ('hedera_cookies', true); localStorage.setItem ('hederaCookies', true);
Htk.Toast.showWarning (_('By using this site you accept cookies')); Htk.Toast.showWarning (_('By using this site you accept cookies'));
} }
} }

View File

@ -14,10 +14,10 @@ Vn.Login = new Class
,set: function (x) ,set: function (x)
{ {
this.link ({_conn: x}, {'loading-changed': this._onConnLoadChange}); this.link ({_conn: x}, {'loading-changed': this._onConnLoadChange});
/* x.execQuery ( x.execQuery (
'SELECT title, link, icon FROM social ORDER BY priority', 'SELECT title, link, icon FROM social ORDER BY priority',
this._onSocialQueryDone.bind (this)); this._onSocialQueryDone.bind (this));
*/ } }
,get: function () ,get: function ()
{ {
return this._conn; return this._conn;
@ -100,20 +100,21 @@ Vn.Login = new Class
,onPasswordLost: function () ,onPasswordLost: function ()
{ {
if (!this.$('user').value) var user = this.$('user').value;
{
if (!user)
Htk.Toast.showError (_('Please write your user name')); Htk.Toast.showError (_('Please write your user name'));
return; else
this._conn.send ('core/recover-password', {'user': user},
this._onPasswordRecovered.bind (this));
} }
var request = new Vn.JsonRequest ('core/recover-password'); ,_onPasswordRecovered: function (json, error)
request.send (null, this._onPasswordRecovered.bind (this));
}
,_onPasswordRecovered: function (request, json, error)
{ {
if (json) if (json)
Htk.Toast.showMessage (_('It sent an email with your new password')); Htk.Toast.showMessage (_('A mail has been sent with your new password'));
else
Htk.Toast.showError (error.message);
} }
,_onSocialQueryDone: function (resultSet) ,_onSocialQueryDone: function (resultSet)

237
js/vn/json-connection.js Normal file
View File

@ -0,0 +1,237 @@
/**
* Handler for JSON rest connections.
**/
Vn.JsonConnection = new Class
({
Extends: Vn.Object
,_connected: false
,_requestsCount: 0
,_token: null
/**
* Initilizes the connection object.
**/
,initialize: function ()
{
this.parent ();
if (localStorage.getItem ('token'))
this._token = localStorage.getItem ('token');
if (sessionStorage.getItem ('token'))
this._token = sessionStorage.getItem ('token');
}
/**
* Opens the connection to the REST service.
*
* @param {string} user The user name
* @param {String} password The user password
* @param {Boolean} remember Specifies if the user should be remembered
* @param {Function} openCallback The function to call when operation is done
**/
,open: function (user, pass, remember, callback)
{
if (user != null)
{
var params = {
'user': user
,'password': pass
,'remember': remember
};
}
else
var params = null;
this.send ('core/login', params,
this._onOpen.bind (this, callback, remember));
}
/*
* Called when open operation is done.
*/
,_onOpen: function (callback, remember, json, error)
{
if (json && json.login)
{
this._connected = true;
this._token = json.token;
var storage = remember ? localStorage : sessionStorage;
storage.setItem ('token', this._token);
this.signalEmit ('openned');
}
if (callback)
callback (this, this._connected, error);
}
/**
* Closes the connection to the REST service.
*
* @param {Function} callback The function to call when operation is done
**/
,close: function (callback)
{
this.send ('core/logout', null,
this._onClose.bind (this, callback));
}
/*
* Called when close operation is done.
*/
,_onClose: function (callback, json, error)
{
this._connected = false;
this.signalEmit ('closed');
if (callback)
callback (this, json == true, error);
}
/**
* Executes the specified REST service with the given params and calls
* the callback when response is received.
*
* @param {String} restService The service path
* @param {Map} params The params to pass to the service
* @param {Function} callback The response callback
**/
,send: function (restService, params, callback)
{
if (!params)
params = {};
params['srv'] = 'json:'+ restService;
this.sendWithUrl (params, callback, 'post', '.');
}
,sendForm: function (form, callback)
{
var params = {};
var elements = form.elements;
for (var i = 0; i < elements.length; i++)
if (elements[i].name)
params[elements[i].name] = elements[i].value;
this.sendWithUrl (params, callback, 'post', form.action);
}
,sendFormMultipart: function (form, callback)
{
var formData = new FormData (form);
if (this._token)
formData.append ('token', this._token);
var request = new XMLHttpRequest ();
request.open ('post', form.action, true);
request.onreadystatechange =
this._onStateChange.bind (this, request, callback);
request.send (formData);
this._addRequest ();
}
/*
* Called when REST response is received.
*/
,sendWithUrl: function (params, callback, method, url)
{
if (this._token)
params['token'] = this._token;
var request = new XMLHttpRequest ();
request.open (method, url, true);
request.setRequestHeader ('Content-Type',
'application/x-www-form-urlencoded');
request.onreadystatechange =
this._onStateChange.bind (this, request, callback);
request.send (Vn.Url.makeUri (params));
this._addRequest ();
}
,_addRequest: function ()
{
this._requestsCount++;
if (this._requestsCount === 1)
this.signalEmit ('loading-changed', true);
}
,_onStateChange: function (request, callback)
{
if (request.readyState !== 4)
return;
this._requestsCount--;
if (this._requestsCount === 0)
this.signalEmit ('loading-changed', false);
var data = null;
var error = null;
try {
if (request.status == 0)
{
var ex = new Vn.JsonException ();
ex.message = _('The server does not respond');
throw ex;
}
var contentType = null;
try {
contentType = request
.getResponseHeader ('Content-Type')
.split (';')[0]
.trim ();
}
catch (e) {}
if (contentType != 'application/json')
{
var ex = new Vn.JsonException ();
ex.message = request.statusText;
ex.code = request.status;
throw ex;
}
var json = JSON.parse (request.responseText);
var jsData = json.data;
var jsWarns = json.warnings;
if (request.status == 200)
{
data = jsData;
}
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)
{
data = null;
error = e;
}
if (error)
this.signalEmit ('error', error);
if (callback)
callback (data, error);
}
});

View File

@ -1,116 +0,0 @@
/**
* Handler for JSON rest requests.
**/
Vn.JsonRequest = new Class
({
initialize: function (methodName)
{
this._methodName = methodName;
}
,sendWithUrl: function (params, callback, method, url)
{
var request = new XMLHttpRequest ();
request.open (method, url, true);
request.setRequestHeader ('Content-Type',
'application/x-www-form-urlencoded');
request.onreadystatechange =
this._onStateChange.bind (this, request, callback);
request.send (Vn.Url.makeUri (params));
}
,send: function (params, callback)
{
if (!params)
params = {};
params['srv'] = 'json:'+ this._methodName;
this.sendWithUrl (params, callback, 'post', '.');
}
,sendForm: function (form, callback)
{
var params = {};
var elements = form.elements;
for (var i = 0; i < elements.length; i++)
if (elements[i].name)
params[elements[i].name] = elements[i].value;
this.sendWithUrl (params, callback, 'post', form.action);
}
,sendFormMultipart: function (form, callback)
{
var request = new XMLHttpRequest ();
request.open ('post', form.action, true);
request.onreadystatechange =
this._onStateChange.bind (this, request, callback);
request.send (new FormData (form));
}
,_onStateChange: function (request, callback)
{
if (request.readyState !== 4)
return;
var data = null;
var error = null;
try {
if (request.status == 0)
{
var ex = new Vn.JsonException ();
ex.message = _('The server does not respond');
throw ex;
}
var contentType = null;
try {
contentType = request
.getResponseHeader ('Content-Type')
.split (';')[0]
.trim ();
}
catch (e) {}
if (contentType != 'application/json')
{
var ex = new Vn.JsonException ();
ex.message = request.statusText;
ex.code = request.status;
throw ex;
}
var json = JSON.parse (request.responseText);
var jsData = json.data;
var jsWarns = json.warnings;
if (request.status == 200)
{
data = jsData;
}
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)
{
data = null;
error = e;
}
if (callback)
callback (this, data, error);
}
});

View File

@ -16,6 +16,6 @@ Vn.includeLib ('vn',
,'node' ,'node'
,'builder' ,'builder'
,'json-exception' ,'json-exception'
,'json-request' ,'json-connection'
]); ]);

View File

@ -16,7 +16,7 @@ var Vn =
{ {
if (this._version === undefined) if (this._version === undefined)
{ {
var re = /[; ]vn_version=([^\\s;]*)/; var re = /[; ]vnVersion=([^\\s;]*)/;
var sMatch = (' '+ document.cookie).match (re); var sMatch = (' '+ document.cookie).match (re);
this._version = (sMatch) ? '?'+ unescape (sMatch[1]) : ''; this._version = (sMatch) ? '?'+ unescape (sMatch[1]) : '';
} }

View File

@ -6,7 +6,7 @@ require_once ('Text/CAPTCHA.php');
class Captcha extends Vn\Web\RestRequest class Captcha extends Vn\Web\RestRequest
{ {
function run () function run ($db)
{ {
$options = $options =
[ [

View File

@ -11,7 +11,7 @@ class Log extends Vn\Web\JsonRequest
,'stack' ,'stack'
]; ];
function run () function run ($db)
{ {
$user = isset ($_SESSION['user']) ? $_SESSION['user'] : 'guest'; $user = isset ($_SESSION['user']) ? $_SESSION['user'] : 'guest';
error_log (sprintf ("Javascript: User: %s: %s(%d): %s.\n%s" error_log (sprintf ("Javascript: User: %s: %s(%d): %s.\n%s"

View File

@ -3,31 +3,43 @@
require_once ('vn/web/json-request.php'); require_once ('vn/web/json-request.php');
require_once ('vn/web/jwt.php'); require_once ('vn/web/jwt.php');
const MIN = 60;
const HOUR = 60 * MIN;
const DAY = 24 * HOUR;
const WEEK = 7 * DAY;
class Login extends Vn\Web\JsonRequest class Login extends Vn\Web\JsonRequest
{ {
function run () function run ($db)
{ {
$token = Jwt::encode ([ $this->updateCredentials ($db);
if (isset ($_POST['remember']))
$tokenLife = WEEK;
else
$tokenLife = 30 * MIN;
$token = Vn\Web\Jwt::encode ([
'userName' => $_SESSION['user'], 'userName' => $_SESSION['user'],
'timestamp' => time () 'timestamp' => time (),
'exp' => time () + 7 * 24 * 60 * 60 'exp' => time () + $tokenLife
]); ]);
$this->updateCredentials (); return [
return $token; 'login' => TRUE,
'token' => $token
];
} }
/** /**
* Updates the user credentials in other user databases like Samba. * Updates the user credentials in other user databases like Samba.
**/ **/
function updateCredentials () function updateCredentials ($db)
{ {
$db = $this->getSysConn ();
$hasAccount = $db->getValue ( $hasAccount = $db->getValue (
'SELECT COUNT(*) > 0 'SELECT COUNT(*) > 0
FROM account.user u FROM account.user u
JOIN account.account a ON u.id = a.user_id JOIN account.account a ON u.id = a.id
WHERE u.name = #', WHERE u.name = #',
[$_SESSION['user']] [$_SESSION['user']]
); );

View File

@ -4,7 +4,7 @@ require_once ('vn/web/json-request.php');
class Logout extends Vn\Web\JsonRequest class Logout extends Vn\Web\JsonRequest
{ {
function run () function run ($db)
{ {
$this->logout (); $this->logout ();
return TRUE; return TRUE;

View File

@ -3,17 +3,15 @@
require_once ('vn/web/json-request.php'); require_once ('vn/web/json-request.php');
use Vn\Lib; use Vn\Lib;
use Vn\Web\Security;
class Query extends Vn\Web\JsonRequest class Query extends Vn\Web\JsonRequest
{ {
const PARAMS = ['sql']; const PARAMS = ['sql'];
const SECURITY = Security::INVOKER;
function run ($db) function run ($db)
{ {
$password = $db->getValue (
'SELECT password FROM user WHERE name = #', $_SESSION['user']);
$userDb = $this->createConnection ($_SESSION['user'], $password);
$results = []; $results = [];
try { try {

View File

@ -21,20 +21,20 @@ class RecoverPassword extends Vn\Web\JsonRequest
return TRUE; return TRUE;
$restrictions = $db->getRow ( $restrictions = $db->getRow (
'SELECT length, nupper, ndigits, npunct FROM account.user_password'); 'SELECT length, nUpper, nDigits, nPunct FROM account.userPassword');
$pass = []; $pass = [];
$newPass = ''; $newPass = '';
$nAlpha = $restrictions['length'] - ( $nAlpha = $restrictions['length'] - (
$restrictions['nupper'] + $restrictions['nUpper'] +
$restrictions['ndigits'] + $restrictions['nDigits'] +
$restrictions['npunct']); $restrictions['nPunct']);
$this->genRands ($pass, self::LOWERS, $nAlpha); $this->genRands ($pass, self::LOWERS, $nAlpha);
$this->genRands ($pass, self::UPPERS, $restrictions['nupper']); $this->genRands ($pass, self::UPPERS, $restrictions['nUpper']);
$this->genRands ($pass, self::DIGITS, $restrictions['ndigits']); $this->genRands ($pass, self::DIGITS, $restrictions['nDigits']);
$this->genRands ($pass, self::SYMBOLS, $restrictions['npunct']); $this->genRands ($pass, self::SYMBOLS, $restrictions['nPunct']);
for ($i = count ($pass) - 1; $i >= 0; $i--) for ($i = count ($pass) - 1; $i >= 0; $i--)
{ {

View File

@ -9,13 +9,11 @@ use Vn\Lib;
**/ **/
class Add extends Vn\Web\JsonRequest class Add extends Vn\Web\JsonRequest
{ {
function run () function run ($db)
{ {
// XXX: Uncomment only to test the script // XXX: Uncomment only to test the script
//$_REQUEST['description'] = 'description'; //$_REQUEST['description'] = 'description';
$db = $this->getSysConn ();
$description = empty ($_REQUEST['description']) ? $description = empty ($_REQUEST['description']) ?
NULL : $_REQUEST['description']; NULL : $_REQUEST['description'];

View File

@ -3,9 +3,12 @@
require_once ('vn/web/rest-request.php'); require_once ('vn/web/rest-request.php');
require_once ('vn/web/util.php'); require_once ('vn/web/util.php');
use Vn\Web\Security;
class Invoice extends Vn\Web\RestRequest class Invoice extends Vn\Web\RestRequest
{ {
const PARAMS = ['invoice']; const PARAMS = ['invoice'];
const SECURITY = Security::INVOKER;
function run ($db) function run ($db)
{ {

View File

@ -16,7 +16,7 @@ class Contact extends Vn\Web\JsonRequest
,'captcha' ,'captcha'
]; ];
function run () function run ($db)
{ {
// Checks the antispam code // Checks the antispam code
@ -28,8 +28,6 @@ class Contact extends Vn\Web\JsonRequest
// Sends the mail // Sends the mail
$db = $this->getSysConn ();
// TODO: Change form fields // TODO: Change form fields
//$db->queryFromFile (__DIR__.'/contact', $_REQUEST); //$db->queryFromFile (__DIR__.'/contact', $_REQUEST);
//$customerId = $db->getValue ('SELECT @id'); //$customerId = $db->getValue ('SELECT @id');

View File

@ -8,9 +8,8 @@ require_once ('vn/lib/method.php');
**/ **/
class ExchangeRate extends Vn\Lib\Method class ExchangeRate extends Vn\Lib\Method
{ {
function run () function run ($db)
{ {
$db = $this->getSysConn ();
$db->selectDb ('vn2008'); $db->selectDb ('vn2008');
// Indica la URL del archivo // Indica la URL del archivo

View File

@ -5,9 +5,8 @@ require_once ('libphp-phpmailer/PHPMailerAutoload.php');
class Mail extends Vn\Lib\Method class Mail extends Vn\Lib\Method
{ {
function run () function run ($db)
{ {
$db = $this->getSysConn ();
$db->selectDb ('vn2008'); $db->selectDb ('vn2008');
$db->query ('START TRANSACTION'); $db->query ('START TRANSACTION');

View File

@ -4,9 +4,8 @@ require_once ('vn/lib/method.php');
class VisitsSync extends Vn\Lib\Method class VisitsSync extends Vn\Lib\Method
{ {
function run () function run ($db)
{ {
$db = $this->getSysConn ();
$result = $db->query ("SELECT id, agent FROM visit_agent $result = $db->query ("SELECT id, agent FROM visit_agent
WHERE version = '0.0' OR platform = 'unknown' OR cookies IS NULL ORDER BY id DESC"); WHERE version = '0.0' OR platform = 'unknown' OR cookies IS NULL ORDER BY id DESC");

View File

@ -8,10 +8,8 @@ require_once (__DIR__.'/tpv.php');
**/ **/
class ConfirmMail extends Vn\Lib\Method class ConfirmMail extends Vn\Lib\Method
{ {
function run () function run ($db)
{ {
$db = $this->getSysConn ();
$imap = NULL; $imap = NULL;
$imapConf = $db->getRow ( $imapConf = $db->getRow (
'SELECT host, user, pass, clean_period, success_folder, error_folder 'SELECT host, user, pass, clean_period, success_folder, error_folder

View File

@ -8,7 +8,7 @@ require_once (__DIR__.'/tpv.php');
**/ **/
class ConfirmPost extends Vn\Web\RestRequest class ConfirmPost extends Vn\Web\RestRequest
{ {
function run () function run ($db)
{ {
Tpv::confirm ($db, $_POST); Tpv::confirm ($db, $_POST);
} }

View File

@ -9,7 +9,7 @@ require_once (__DIR__.'/tpv.php');
**/ **/
class ConfirmSoap extends Vn\Web\RestRequest class ConfirmSoap extends Vn\Web\RestRequest
{ {
function run () function run ($db)
{ {
global $tpvConfirmSoap; global $tpvConfirmSoap;
@ -26,7 +26,7 @@ function procesaNotificacionSIS ($XML)
{ {
global $tpvConfirmSoap; global $tpvConfirmSoap;
$db = $tpvConfirmSoap->getSysConn (); $db = $tpvConfirmSoap->app->getSysConn ();
$status = 'OK'; $status = 'OK';
$requestString = $XML; $requestString = $XML;

View File

@ -3,7 +3,6 @@
namespace Vn\Web; namespace Vn\Web;
require_once ('vn/lib/app.php'); require_once ('vn/lib/app.php');
require_once (__DIR__.'/jwt.php');
/** /**
* Main class for web applications. * Main class for web applications.
@ -48,6 +47,8 @@ class App extends \Vn\Lib\App
http_response_code (400); http_response_code (400);
} }
function deinit () {}
/** /**
* Gets the configuration file name associated to the current vhost * Gets the configuration file name associated to the current vhost
* or the default config file if isn't defined a file for the vhost. * or the default config file if isn't defined a file for the vhost.
@ -58,8 +59,11 @@ class App extends \Vn\Lib\App
&& preg_match ('/^[\w\-\.]+$/', $_SERVER['SERVER_NAME'])) && preg_match ('/^[\w\-\.]+$/', $_SERVER['SERVER_NAME']))
{ {
$hostSplit = explode ('.', $_SERVER['SERVER_NAME']); $hostSplit = explode ('.', $_SERVER['SERVER_NAME']);
array_splice ($hostSplit, -2);
$subdomain = implode ('.', $hostSplit);
$configDir = _CONFIG_DIR .'/'. $this->name; $configDir = _CONFIG_DIR .'/'. $this->name;
$hostFile = "$configDir/config/{$hostSplit[0]}.php"; $hostFile = "$configDir/config.$subdomain.php";
} }
if (isset ($hostFile) && file_exists ($hostFile)) if (isset ($hostFile) && file_exists ($hostFile))

View File

@ -2,7 +2,7 @@
namespace Vn\Web; namespace Vn\Web;
class DbSessionHandler implements SessionHandlerInterface class DbSessionHandler implements \SessionHandlerInterface
{ {
private $db; private $db;
@ -18,13 +18,13 @@ class DbSessionHandler implements SessionHandlerInterface
function destroy ($sessionId) function destroy ($sessionId)
{ {
$db->query ('DELETE FROM userSession WHERE ssid = #', [$sessionId]); $this->db->query ('DELETE FROM userSession WHERE ssid = #', [$sessionId]);
return TRUE; return TRUE;
} }
function gc ($maxLifeTime) function gc ($maxLifeTime)
{ {
$db->query ('DELETE FROM userSession $this->db->query ('DELETE FROM userSession
WHERE lastUpdate < TIMESTAMPADD(SECOND, -#, NOW())', WHERE lastUpdate < TIMESTAMPADD(SECOND, -#, NOW())',
[$maxLifeTime] [$maxLifeTime]
); );
@ -39,14 +39,14 @@ class DbSessionHandler implements SessionHandlerInterface
function read ($sessionId) function read ($sessionId)
{ {
//$db->query ('DO GET_LOCK(#, 30)', [$sessionId]); //$db->query ('DO GET_LOCK(#, 30)', [$sessionId]);
$sessionData = $db->getValue ( $sessionData = $this->db->getValue (
'SELECT data FROM userSession WHERE ssid = #', [$sessionId]); 'SELECT data FROM userSession WHERE ssid = #', [$sessionId]);
return isset ($sessionData) ? $sessionData : ''; return isset ($sessionData) ? $sessionData : '';
} }
function write ($sessionId, $sessionData) function write ($sessionId, $sessionData)
{ {
$db->query ('REPLACE INTO userSession SET ssid = #, data = #', $this->db->query ('REPLACE INTO userSession SET ssid = #, data = #',
[$sessionId, $sessionData]); [$sessionId, $sessionData]);
//$db->query ('DO RELEASE_LOCK(#)', [$sessionId]); //$db->query ('DO RELEASE_LOCK(#)', [$sessionId]);
return TRUE; return TRUE;

View File

@ -13,7 +13,7 @@ class HtmlService extends Service
{ {
function run () function run ()
{ {
$db = $this->app->getSysConn (); $db = $this->db;
if (!$this->isHttps () if (!$this->isHttps ()
&& $db->getValue ('SELECT https FROM config')) && $db->getValue ('SELECT https FROM config'))
@ -70,7 +70,7 @@ class HtmlService extends Service
// Setting the version // Setting the version
setcookie ('vn_version', $this->getVersion ()); setcookie ('vnVersion', $this->getVersion ());
// Loading the requested page // Loading the requested page
@ -125,7 +125,7 @@ class HtmlService extends Service
$this->includeJs ($localeJs); $this->includeJs ($localeJs);
for ($i = 1; $i < count ($args); $i++) for ($i = 1; $i < count ($args); $i++)
$this->includeJs ("js/$libName/${args[$i]}.js"); $this->includeJs ("js/$libName/{$args[$i]}.js");
} }
function includeCss ($fileName) function includeCss ($fileName)

View File

@ -25,16 +25,14 @@ class JsonService extends RestService
// Checks the client version // Checks the client version
if (!empty ($_COOKIE['vn_version'])) if (!empty ($_COOKIE['vnVersion']))
$clientVersion = (int) $_COOKIE['vn_version']; $clientVersion = (int) $_COOKIE['vnVersion'];
if (isset ($clientVersion) if (isset ($clientVersion)
&& $clientVersion < $this->getVersion ()) && $clientVersion < $this->getVersion ())
throw new OutdatedVersionException (); throw new OutdatedVersionException ();
$method = $this->app->loadMethod ( $json = $this->loadMethod (__NAMESPACE__.'\JsonRequest');
$_REQUEST['method'], __NAMESPACE__.'\JsonRequest', './rest');
$json = $method->runRest ();
$this->replyJson ($json); $this->replyJson ($json);
} }

View File

@ -4,7 +4,11 @@ namespace Vn\Web;
require_once (__DIR__.'/rest-service.php'); require_once (__DIR__.'/rest-service.php');
use Vn\Lib; class Security
{
const DEFINER = 1;
const INVOKER = 2;
}
/** /**
* Base class for REST services. * Base class for REST services.
@ -12,43 +16,7 @@ use Vn\Lib;
abstract class RestRequest extends \Vn\Lib\Method abstract class RestRequest extends \Vn\Lib\Method
{ {
const PARAMS = NULL; const PARAMS = NULL;
const LOGIN_REQUIRED = TRUE; const SECURITY = Security::DEFINER;
function runRest ()
{
try {
$db = $this->login ();
}
catch (Exception $e)
{
if (self::LOGIN_REQUIRED)
throw $e;
}
if (self::PARAMS !== NULL && !$this->checkParams ($_REQUEST, self::PARAMS))
throw new Lib\UserException (s('Missing parameters'));
return $this->run ($db);
}
/**
* Authenticates the user agaisnt database and returns its associated
* database connection.
*
* return Db\Conn The database connection
**/
function login ()
{
return $this->app->login ();
}
/**
* Logouts the current user.
**/
function logout ()
{
$this->app->logout ();
}
} }
?> ?>

View File

@ -19,22 +19,7 @@ class RestService extends Service
set_exception_handler ([$this, 'exceptionHandler']); set_exception_handler ([$this, 'exceptionHandler']);
$this->startSession (); $this->startSession ();
$this->loadMethod (__NAMESPACE__.'\RestRequest');
$method = $this->app->loadMethod (
$_REQUEST['method'], __NAMESPACE__.'\RestRequest', './rest');
$method->runRest ();
}
/**
* 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) function statusFromException ($e)

View File

@ -3,24 +3,26 @@
namespace Vn\Web; namespace Vn\Web;
require_once ('vn/lib/app.php'); require_once ('vn/lib/app.php');
require_once (__DIR__.'/jwt.php');
require_once (__DIR__.'/db-session-handler.php'); require_once (__DIR__.'/db-session-handler.php');
use Vn\Lib\Locale; use Vn\Lib\Locale;
use Vn\Lib\UserException;
/** /**
* Thrown when user credentials could not be fetched. * Thrown when user credentials could not be fetched.
**/ **/
class SessionExpiredException extends Lib\UserException {} class SessionExpiredException extends UserException {}
/** /**
* Thrown when user credentials are invalid. * Thrown when user credentials are invalid.
**/ **/
class BadLoginException extends Lib\UserException {} class BadLoginException extends UserException {}
/** /**
* Thrown when client version is outdated. * Thrown when client version is outdated.
**/ **/
class OutdatedVersionException extends Lib\UserException {} class OutdatedVersionException extends UserException {}
/** /**
* Main class for web applications. * Main class for web applications.
@ -28,10 +30,13 @@ class OutdatedVersionException extends Lib\UserException {}
abstract class Service abstract class Service
{ {
protected $app; protected $app;
protected $db;
protected $userDb = NULL;
function __construct ($app) function __construct ($app)
{ {
$this->app = $app; $this->app = $app;
$this->db = $app->getSysConn ();
} }
/** /**
@ -39,12 +44,12 @@ abstract class Service
**/ **/
function startSession () function startSession ()
{ {
$db = $this->app->getSysConn (); $db = $this->db;
ini_set ('session.cookie_secure', TRUE); ini_set ('session.cookie_secure', TRUE);
ini_set ('session.use_only_cookies', FALSE); ini_set ('session.use_only_cookies', FALSE);
ini_set ('session.cookie_path', 'cookies'); ini_set ('session.cookie_path', 'cookies');
ini_set ('session.hash_function', 'sha512'); ini_set ('session.hash_function', 'sha256');
session_set_save_handler (new DbSessionHandler ($db)); session_set_save_handler (new DbSessionHandler ($db));
session_start (); session_start ();
@ -128,7 +133,7 @@ abstract class Service
**/ **/
function login () function login ()
{ {
$db = $this->getSysConn (); $db = $this->db;
$user = NULL; $user = NULL;
$wasLoged = isset ($_SESSION['user']); $wasLoged = isset ($_SESSION['user']);
@ -175,7 +180,7 @@ abstract class Service
// Registering the user access // Registering the user access
if (isset ($_SESSION['access']) if (isset ($_SESSION['access'])
&& (!isset ($_SESSION['visitUser'] || $wasLoged))) && (!isset ($_SESSION['visitUser']) || $wasLoged))
{ {
$_SESSION['visitUser'] = TRUE; $_SESSION['visitUser'] = TRUE;
@ -184,15 +189,6 @@ abstract class Service
[$_SESSION['access'], session_id ()] [$_SESSION['access'], session_id ()]
); );
} }
$db->query ('CALL userSessionStart (#)', [session_id ()]);
}
function deinit ()
{
$db = $this->getSysConn ();
$db->query ('CALL userSessionEnd ()');
$db->query ('CALL account.userLogout ()');
} }
/** /**
@ -204,6 +200,56 @@ abstract class Service
unset ($_SESSION['user']); unset ($_SESSION['user']);
} }
/**
* Creates or returns a database connection where the authenticated user
* is the current logged user.
*
* @return {Db\Conn} The database connection
**/
function getUserDb ($user)
{
if ($this->userDb)
return $this->userDb;
$password = $sysDb->getValue (
'SELECT password FROM user WHERE name = #', [$user]);
return $this->userDb = $this->createConnection ($user, $password);
}
/**
* Runs a method.
**/
function loadMethod ($class)
{
$db = $this->db;
$this->login ();
$method = $this->app->loadMethod (
$_REQUEST['method'], $class, './rest');
if ($method::SECURITY == Security::DEFINER)
{
$isAuthorized = $db->getValue ('SELECT userCheckRestPriv (#)',
[$_REQUEST['method']]);
if (!$isAuthorized)
throw new UserException ('You don\'t have enough privileges');
$methodDb = $db;
}
else
$methodDb = $this->getUserDb ();
if ($method::PARAMS !== NULL && !$method->checkParams ($_REQUEST, $method::PARAMS))
throw new UserException (s('Missing parameters'));
$res = $method->run ($methodDb);
$db->query ('CALL account.userLogout ()');
return $res;
}
/** /**
* Checks if the HTTP connection is secure. * Checks if the HTTP connection is secure.
* *