diff --git a/forms/ecomerce/catalog/catalog.js b/forms/ecomerce/catalog/catalog.js index d11a2335..95f4f064 100644 --- a/forms/ecomerce/catalog/catalog.js +++ b/forms/ecomerce/catalog/catalog.js @@ -34,8 +34,8 @@ Vn.Catalog = new Class this.$('items-model').setInfo ('a', 'Articles', 'vn2008', ['item_id']); - if (Vn.Cookie.check ('hedera_view')) - this.setView (Vn.Cookie.getInt ('hedera_view')); + if (localStorage.getItem ('hederaView')) + this.setView (parsetInt (localStorage.getItem ('hederaView'))); else this.setView (Vn.Catalog.View.GRID); } @@ -70,7 +70,7 @@ Vn.Catalog = new Class var node = this.$('grid-view').getNode (); node.className = className; - Vn.Cookie.set ('hedera_view', this.view); + localStorage.setItem ('hederaView', this.view); } ,onSwitchViewClick: function () diff --git a/js/db/conn.js b/js/db/conn.js index 61d88834..3cb637af 100644 --- a/js/db/conn.js +++ b/js/db/conn.js @@ -26,93 +26,7 @@ Db.Conn = new Class ().extend Db.Conn.implement ({ - Extends: Vn.Object - - ,_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); - } + Extends: Vn.JsonConnection /** * Runs a SQL query on the database. @@ -122,13 +36,7 @@ Db.Conn.implement **/ ,execSql: function (sql, callback) { - this._requestsCount++; - - if (this._requestsCount === 1) - this.signalEmit ('loading-changed', true); - - var request = new Vn.JsonRequest ('core/query'); - request.send ({'sql': sql}, + this.send ('core/query', {'sql': sql}, this._onExec.bind (this, callback)); } @@ -167,13 +75,8 @@ Db.Conn.implement /* * 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) try { if (json && json instanceof Array) diff --git a/js/hedera/app.js b/js/hedera/app.js index 214df51b..61a3adda 100644 --- a/js/hedera/app.js +++ b/js/hedera/app.js @@ -118,21 +118,28 @@ Vn.App = new Class ,_onConnError: function (conn, error) { if (error instanceof Vn.JsonException) - switch (error.exception) { - case 'Vn\\Web\\BadLoginException': - Htk.Toast.showError (_('Invalid login')); - this._logout (); - break; - case 'Vn\\Web\\SessionExpiredException': - Htk.Toast.showError (_('You\'ve been too idle')); - this._logout (); - break; - case 'Vn\\Web\\OutdatedVersionException': - this._newVersion (error); - break; - default: - Htk.Toast.showError (error.message); + var exception = error.exception + .replace (/\\/g, '.') + .replace (/Exception$/, '') + .replace (/^Vn\.Web\./, ''); + + switch (exception) + { + case 'BadLogin': + Htk.Toast.showError (_('Invalid login')); + this._logout (); + break; + case 'SessionExpired': + Htk.Toast.showError (_('You\'ve been too idle')); + this._logout (); + break; + case 'OutdatedVersion': + this._newVersion (error); + break; + default: + Htk.Toast.showError (error.message); + } } else { @@ -168,9 +175,7 @@ Vn.App = new Class ,'message': error.message ,'stack': error.stack }; - - var request = new Vn.JsonRequest ('core/log'); - request.send (params); + this._conn.send ('core/log', params); } ,_freeLogin: function () diff --git a/js/hedera/gui.js b/js/hedera/gui.js index 34bab537..b28a5fda 100644 --- a/js/hedera/gui.js +++ b/js/hedera/gui.js @@ -84,9 +84,9 @@ Vn.Gui = new Class this.formParam = new Vn.HashParam ({key: 'form'}); 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')); } } diff --git a/js/hedera/login.js b/js/hedera/login.js index f4c72ab3..2e640484 100644 --- a/js/hedera/login.js +++ b/js/hedera/login.js @@ -14,10 +14,10 @@ Vn.Login = new Class ,set: function (x) { this.link ({_conn: x}, {'loading-changed': this._onConnLoadChange}); -/* x.execQuery ( + x.execQuery ( 'SELECT title, link, icon FROM social ORDER BY priority', this._onSocialQueryDone.bind (this)); -*/ } + } ,get: function () { return this._conn; @@ -100,20 +100,21 @@ Vn.Login = new Class ,onPasswordLost: function () { - if (!this.$('user').value) - { - Htk.Toast.showError (_('Please write your user name')); - return; - } + var user = this.$('user').value; - var request = new Vn.JsonRequest ('core/recover-password'); - request.send (null, this._onPasswordRecovered.bind (this)); + if (!user) + Htk.Toast.showError (_('Please write your user name')); + else + this._conn.send ('core/recover-password', {'user': user}, + this._onPasswordRecovered.bind (this)); } - ,_onPasswordRecovered: function (request, json, error) + ,_onPasswordRecovered: function (json, error) { 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) diff --git a/js/vn/json-connection.js b/js/vn/json-connection.js new file mode 100644 index 00000000..09a93f91 --- /dev/null +++ b/js/vn/json-connection.js @@ -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); + } +}); + diff --git a/js/vn/json-request.js b/js/vn/json-request.js deleted file mode 100644 index 856f522d..00000000 --- a/js/vn/json-request.js +++ /dev/null @@ -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); - } -}); - diff --git a/js/vn/main.js b/js/vn/main.js index 83a93c81..84cb0192 100644 --- a/js/vn/main.js +++ b/js/vn/main.js @@ -16,6 +16,6 @@ Vn.includeLib ('vn', ,'node' ,'builder' ,'json-exception' - ,'json-request' + ,'json-connection' ]); diff --git a/js/vn/vn.js b/js/vn/vn.js index 833db179..e0b19a66 100644 --- a/js/vn/vn.js +++ b/js/vn/vn.js @@ -16,7 +16,7 @@ var Vn = { if (this._version === undefined) { - var re = /[; ]vn_version=([^\\s;]*)/; + var re = /[; ]vnVersion=([^\\s;]*)/; var sMatch = (' '+ document.cookie).match (re); this._version = (sMatch) ? '?'+ unescape (sMatch[1]) : ''; } diff --git a/rest/core/captcha.php b/rest/core/captcha.php index 32296d21..182c3283 100755 --- a/rest/core/captcha.php +++ b/rest/core/captcha.php @@ -6,7 +6,7 @@ require_once ('Text/CAPTCHA.php'); class Captcha extends Vn\Web\RestRequest { - function run () + function run ($db) { $options = [ diff --git a/rest/core/log.php b/rest/core/log.php index 4e7a19a7..4471e6fd 100755 --- a/rest/core/log.php +++ b/rest/core/log.php @@ -11,7 +11,7 @@ class Log extends Vn\Web\JsonRequest ,'stack' ]; - function run () + function run ($db) { $user = isset ($_SESSION['user']) ? $_SESSION['user'] : 'guest'; error_log (sprintf ("Javascript: User: %s: %s(%d): %s.\n%s" diff --git a/rest/core/login.php b/rest/core/login.php index 2cfb3fd7..ef1672d7 100755 --- a/rest/core/login.php +++ b/rest/core/login.php @@ -3,31 +3,43 @@ require_once ('vn/web/json-request.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 { - 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'], - 'timestamp' => time () - 'exp' => time () + 7 * 24 * 60 * 60 + 'timestamp' => time (), + 'exp' => time () + $tokenLife ]); - - $this->updateCredentials (); - return $token; + + return [ + 'login' => TRUE, + 'token' => $token + ]; } /** * Updates the user credentials in other user databases like Samba. **/ - function updateCredentials () + function updateCredentials ($db) { - $db = $this->getSysConn (); - $hasAccount = $db->getValue ( 'SELECT COUNT(*) > 0 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 = #', [$_SESSION['user']] ); diff --git a/rest/core/logout.php b/rest/core/logout.php index 13497cf2..9836146a 100755 --- a/rest/core/logout.php +++ b/rest/core/logout.php @@ -4,7 +4,7 @@ require_once ('vn/web/json-request.php'); class Logout extends Vn\Web\JsonRequest { - function run () + function run ($db) { $this->logout (); return TRUE; diff --git a/rest/core/query.php b/rest/core/query.php index f77c9a1a..2ee8d77d 100755 --- a/rest/core/query.php +++ b/rest/core/query.php @@ -3,17 +3,15 @@ require_once ('vn/web/json-request.php'); use Vn\Lib; +use Vn\Web\Security; class Query extends Vn\Web\JsonRequest { const PARAMS = ['sql']; + const SECURITY = Security::INVOKER; function run ($db) { - $password = $db->getValue ( - 'SELECT password FROM user WHERE name = #', $_SESSION['user']); - $userDb = $this->createConnection ($_SESSION['user'], $password); - $results = []; try { diff --git a/rest/core/recover-password.php b/rest/core/recover-password.php index 25238cac..cec7e042 100755 --- a/rest/core/recover-password.php +++ b/rest/core/recover-password.php @@ -21,20 +21,20 @@ class RecoverPassword extends Vn\Web\JsonRequest return TRUE; $restrictions = $db->getRow ( - 'SELECT length, nupper, ndigits, npunct FROM account.user_password'); + 'SELECT length, nUpper, nDigits, nPunct FROM account.userPassword'); $pass = []; $newPass = ''; $nAlpha = $restrictions['length'] - ( - $restrictions['nupper'] + - $restrictions['ndigits'] + - $restrictions['npunct']); + $restrictions['nUpper'] + + $restrictions['nDigits'] + + $restrictions['nPunct']); $this->genRands ($pass, self::LOWERS, $nAlpha); - $this->genRands ($pass, self::UPPERS, $restrictions['nupper']); - $this->genRands ($pass, self::DIGITS, $restrictions['ndigits']); - $this->genRands ($pass, self::SYMBOLS, $restrictions['npunct']); + $this->genRands ($pass, self::UPPERS, $restrictions['nUpper']); + $this->genRands ($pass, self::DIGITS, $restrictions['nDigits']); + $this->genRands ($pass, self::SYMBOLS, $restrictions['nPunct']); for ($i = count ($pass) - 1; $i >= 0; $i--) { diff --git a/rest/dms/add.php b/rest/dms/add.php index a5872d8c..0f8630e1 100644 --- a/rest/dms/add.php +++ b/rest/dms/add.php @@ -9,12 +9,10 @@ use Vn\Lib; **/ class Add extends Vn\Web\JsonRequest { - function run () + function run ($db) { // XXX: Uncomment only to test the script //$_REQUEST['description'] = 'description'; - - $db = $this->getSysConn (); $description = empty ($_REQUEST['description']) ? NULL : $_REQUEST['description']; diff --git a/rest/dms/invoice.php b/rest/dms/invoice.php index 979a8a73..2bb7dd4b 100644 --- a/rest/dms/invoice.php +++ b/rest/dms/invoice.php @@ -3,9 +3,12 @@ require_once ('vn/web/rest-request.php'); require_once ('vn/web/util.php'); +use Vn\Web\Security; + class Invoice extends Vn\Web\RestRequest { const PARAMS = ['invoice']; + const SECURITY = Security::INVOKER; function run ($db) { diff --git a/rest/misc/contact.php b/rest/misc/contact.php index ea2c314d..e622422b 100755 --- a/rest/misc/contact.php +++ b/rest/misc/contact.php @@ -16,7 +16,7 @@ class Contact extends Vn\Web\JsonRequest ,'captcha' ]; - function run () + function run ($db) { // Checks the antispam code @@ -27,8 +27,6 @@ class Contact extends Vn\Web\JsonRequest throw new Lib\UserException (s('Wrong captcha'), 'wrongCaptcha'); // Sends the mail - - $db = $this->getSysConn (); // TODO: Change form fields //$db->queryFromFile (__DIR__.'/contact', $_REQUEST); diff --git a/rest/misc/exchange-rate.php b/rest/misc/exchange-rate.php index 0fbfecb2..a01c11bd 100755 --- a/rest/misc/exchange-rate.php +++ b/rest/misc/exchange-rate.php @@ -8,9 +8,8 @@ require_once ('vn/lib/method.php'); **/ class ExchangeRate extends Vn\Lib\Method { - function run () + function run ($db) { - $db = $this->getSysConn (); $db->selectDb ('vn2008'); // Indica la URL del archivo diff --git a/rest/misc/mail.php b/rest/misc/mail.php index 1008df15..654cad01 100755 --- a/rest/misc/mail.php +++ b/rest/misc/mail.php @@ -5,9 +5,8 @@ require_once ('libphp-phpmailer/PHPMailerAutoload.php'); class Mail extends Vn\Lib\Method { - function run () + function run ($db) { - $db = $this->getSysConn (); $db->selectDb ('vn2008'); $db->query ('START TRANSACTION'); diff --git a/rest/misc/visits-sync.php b/rest/misc/visits-sync.php index be8146a5..db64ae47 100644 --- a/rest/misc/visits-sync.php +++ b/rest/misc/visits-sync.php @@ -4,9 +4,8 @@ require_once ('vn/lib/method.php'); class VisitsSync extends Vn\Lib\Method { - function run () + function run ($db) { - $db = $this->getSysConn (); $result = $db->query ("SELECT id, agent FROM visit_agent WHERE version = '0.0' OR platform = 'unknown' OR cookies IS NULL ORDER BY id DESC"); diff --git a/rest/tpv/confirm-mail.php b/rest/tpv/confirm-mail.php index 744ee342..ab28ed17 100644 --- a/rest/tpv/confirm-mail.php +++ b/rest/tpv/confirm-mail.php @@ -8,10 +8,8 @@ require_once (__DIR__.'/tpv.php'); **/ class ConfirmMail extends Vn\Lib\Method { - function run () + function run ($db) { - $db = $this->getSysConn (); - $imap = NULL; $imapConf = $db->getRow ( 'SELECT host, user, pass, clean_period, success_folder, error_folder diff --git a/rest/tpv/confirm-post.php b/rest/tpv/confirm-post.php index 7665f6a4..dc9a27fb 100644 --- a/rest/tpv/confirm-post.php +++ b/rest/tpv/confirm-post.php @@ -8,7 +8,7 @@ require_once (__DIR__.'/tpv.php'); **/ class ConfirmPost extends Vn\Web\RestRequest { - function run () + function run ($db) { Tpv::confirm ($db, $_POST); } diff --git a/rest/tpv/confirm-soap.php b/rest/tpv/confirm-soap.php index 6bfac450..05ab512a 100644 --- a/rest/tpv/confirm-soap.php +++ b/rest/tpv/confirm-soap.php @@ -9,7 +9,7 @@ require_once (__DIR__.'/tpv.php'); **/ class ConfirmSoap extends Vn\Web\RestRequest { - function run () + function run ($db) { global $tpvConfirmSoap; @@ -26,7 +26,7 @@ function procesaNotificacionSIS ($XML) { global $tpvConfirmSoap; - $db = $tpvConfirmSoap->getSysConn (); + $db = $tpvConfirmSoap->app->getSysConn (); $status = 'OK'; $requestString = $XML; diff --git a/vn/web/app.php b/vn/web/app.php index f2420412..0df2100b 100644 --- a/vn/web/app.php +++ b/vn/web/app.php @@ -3,7 +3,6 @@ namespace Vn\Web; require_once ('vn/lib/app.php'); -require_once (__DIR__.'/jwt.php'); /** * Main class for web applications. @@ -47,6 +46,8 @@ class App extends \Vn\Lib\App else http_response_code (400); } + + function deinit () {} /** * Gets the configuration file name associated to the current vhost @@ -58,8 +59,11 @@ class App extends \Vn\Lib\App && preg_match ('/^[\w\-\.]+$/', $_SERVER['SERVER_NAME'])) { $hostSplit = explode ('.', $_SERVER['SERVER_NAME']); + array_splice ($hostSplit, -2); + $subdomain = implode ('.', $hostSplit); + $configDir = _CONFIG_DIR .'/'. $this->name; - $hostFile = "$configDir/config/{$hostSplit[0]}.php"; + $hostFile = "$configDir/config.$subdomain.php"; } if (isset ($hostFile) && file_exists ($hostFile)) diff --git a/vn/web/db-session-handler.php b/vn/web/db-session-handler.php index 4b32901e..0166dcf3 100755 --- a/vn/web/db-session-handler.php +++ b/vn/web/db-session-handler.php @@ -2,7 +2,7 @@ namespace Vn\Web; -class DbSessionHandler implements SessionHandlerInterface +class DbSessionHandler implements \SessionHandlerInterface { private $db; @@ -18,13 +18,13 @@ class DbSessionHandler implements SessionHandlerInterface function destroy ($sessionId) { - $db->query ('DELETE FROM userSession WHERE ssid = #', [$sessionId]); + $this->db->query ('DELETE FROM userSession WHERE ssid = #', [$sessionId]); return TRUE; } function gc ($maxLifeTime) { - $db->query ('DELETE FROM userSession + $this->db->query ('DELETE FROM userSession WHERE lastUpdate < TIMESTAMPADD(SECOND, -#, NOW())', [$maxLifeTime] ); @@ -39,14 +39,14 @@ class DbSessionHandler implements SessionHandlerInterface function read ($sessionId) { //$db->query ('DO GET_LOCK(#, 30)', [$sessionId]); - $sessionData = $db->getValue ( + $sessionData = $this->db->getValue ( 'SELECT data FROM userSession WHERE ssid = #', [$sessionId]); return isset ($sessionData) ? $sessionData : ''; } function write ($sessionId, $sessionData) { - $db->query ('REPLACE INTO userSession SET ssid = #, data = #', + $this->db->query ('REPLACE INTO userSession SET ssid = #, data = #', [$sessionId, $sessionData]); //$db->query ('DO RELEASE_LOCK(#)', [$sessionId]); return TRUE; diff --git a/vn/web/html-service.php b/vn/web/html-service.php index c75980e9..0244ced4 100644 --- a/vn/web/html-service.php +++ b/vn/web/html-service.php @@ -13,7 +13,7 @@ class HtmlService extends Service { function run () { - $db = $this->app->getSysConn (); + $db = $this->db; if (!$this->isHttps () && $db->getValue ('SELECT https FROM config')) @@ -70,7 +70,7 @@ class HtmlService extends Service // Setting the version - setcookie ('vn_version', $this->getVersion ()); + setcookie ('vnVersion', $this->getVersion ()); // Loading the requested page @@ -125,7 +125,7 @@ class HtmlService extends Service $this->includeJs ($localeJs); for ($i = 1; $i < count ($args); $i++) - $this->includeJs ("js/$libName/${args[$i]}.js"); + $this->includeJs ("js/$libName/{$args[$i]}.js"); } function includeCss ($fileName) diff --git a/vn/web/json-service.php b/vn/web/json-service.php index 17bf5466..61548af6 100644 --- a/vn/web/json-service.php +++ b/vn/web/json-service.php @@ -25,16 +25,14 @@ class JsonService extends RestService // Checks the client version - if (!empty ($_COOKIE['vn_version'])) - $clientVersion = (int) $_COOKIE['vn_version']; + if (!empty ($_COOKIE['vnVersion'])) + $clientVersion = (int) $_COOKIE['vnVersion']; if (isset ($clientVersion) && $clientVersion < $this->getVersion ()) throw new OutdatedVersionException (); - $method = $this->app->loadMethod ( - $_REQUEST['method'], __NAMESPACE__.'\JsonRequest', './rest'); - $json = $method->runRest (); + $json = $this->loadMethod (__NAMESPACE__.'\JsonRequest'); $this->replyJson ($json); } diff --git a/vn/web/rest-request.php b/vn/web/rest-request.php index 43f09e2f..675ce383 100644 --- a/vn/web/rest-request.php +++ b/vn/web/rest-request.php @@ -4,7 +4,11 @@ namespace Vn\Web; require_once (__DIR__.'/rest-service.php'); -use Vn\Lib; +class Security +{ + const DEFINER = 1; + const INVOKER = 2; +} /** * Base class for REST services. @@ -12,43 +16,7 @@ use Vn\Lib; abstract class RestRequest extends \Vn\Lib\Method { const PARAMS = NULL; - const LOGIN_REQUIRED = TRUE; - - 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 (); - } + const SECURITY = Security::DEFINER; } ?> diff --git a/vn/web/rest-service.php b/vn/web/rest-service.php index d452763a..961ee961 100644 --- a/vn/web/rest-service.php +++ b/vn/web/rest-service.php @@ -19,22 +19,7 @@ class RestService extends Service set_exception_handler ([$this, 'exceptionHandler']); $this->startSession (); - - $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 (); + $this->loadMethod (__NAMESPACE__.'\RestRequest'); } function statusFromException ($e) diff --git a/vn/web/service.php b/vn/web/service.php index 7e05617f..2d371334 100755 --- a/vn/web/service.php +++ b/vn/web/service.php @@ -3,24 +3,26 @@ namespace Vn\Web; require_once ('vn/lib/app.php'); +require_once (__DIR__.'/jwt.php'); require_once (__DIR__.'/db-session-handler.php'); use Vn\Lib\Locale; +use Vn\Lib\UserException; /** * Thrown when user credentials could not be fetched. **/ -class SessionExpiredException extends Lib\UserException {} +class SessionExpiredException extends UserException {} /** * Thrown when user credentials are invalid. **/ -class BadLoginException extends Lib\UserException {} +class BadLoginException extends UserException {} /** * Thrown when client version is outdated. **/ -class OutdatedVersionException extends Lib\UserException {} +class OutdatedVersionException extends UserException {} /** * Main class for web applications. @@ -28,10 +30,13 @@ class OutdatedVersionException extends Lib\UserException {} abstract class Service { protected $app; + protected $db; + protected $userDb = NULL; function __construct ($app) { $this->app = $app; + $this->db = $app->getSysConn (); } /** @@ -39,12 +44,12 @@ abstract class Service **/ function startSession () { - $db = $this->app->getSysConn (); + $db = $this->db; ini_set ('session.cookie_secure', TRUE); ini_set ('session.use_only_cookies', FALSE); 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_start (); @@ -128,7 +133,7 @@ abstract class Service **/ function login () { - $db = $this->getSysConn (); + $db = $this->db; $user = NULL; $wasLoged = isset ($_SESSION['user']); @@ -175,7 +180,7 @@ abstract class Service // Registering the user access if (isset ($_SESSION['access']) - && (!isset ($_SESSION['visitUser'] || $wasLoged))) + && (!isset ($_SESSION['visitUser']) || $wasLoged)) { $_SESSION['visitUser'] = TRUE; @@ -184,15 +189,6 @@ abstract class Service [$_SESSION['access'], session_id ()] ); } - - $db->query ('CALL userSessionStart (#)', [session_id ()]); - } - - function deinit () - { - $db = $this->getSysConn (); - $db->query ('CALL userSessionEnd ()'); - $db->query ('CALL account.userLogout ()'); } /** @@ -203,6 +199,56 @@ abstract class Service unset ($_SESSION['visitUser']); 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.