diff --git a/scripts/stimulsoft.handler.js b/scripts/stimulsoft.handler.js index 0a44540..70f30d9 100644 --- a/scripts/stimulsoft.handler.js +++ b/scripts/stimulsoft.handler.js @@ -48,11 +48,15 @@ StiHandler.prototype.send = function (data, callback) { request.open('post', this.url, true); request.setRequestHeader('Cache-Control', 'max-age=0, no-cache, no-store, must-revalidate'); request.setRequestHeader('Pragma', 'no-cache'); - let csrf_token = {csrf_token} || Stimulsoft.handler.getCookie('csrftoken'); - if (csrf_token) { - request.setRequestHeader('X-CSRFToken', csrf_token); - request.setRequestHeader('X-CSRF-Token', csrf_token); + + if (this.cookie) + request.setRequestHeader('Cookie', this.cookie); + + if (this.csrfToken) { + request.setRequestHeader('X-CSRFToken', this.csrfToken); + request.setRequestHeader('X-CSRF-Token', this.csrfToken); } + request.timeout = this.timeout * 1000; request.onload = function () { if (request.status === 200) { @@ -99,15 +103,21 @@ StiHandler.prototype.https = function (data, callback) { timeout: this.timeout * 1000, headers: { 'Cache-Control': 'max-age=0, no-cache, no-store, must-revalidate', - 'Pragma': 'no-cache' + 'Pragma': 'no-cache', + 'Cookie': this.cookie, + 'X-CSRFToken': this.csrfToken, + 'X-CSRF-Token': this.csrfToken } } let responseText = ''; - let request = require(uri.protocol.replace(':', '')).request(options, function (response) { + let module = uri.protocol.replace(':', ''); + let request = require(module).request(options, function (response) { + response.on('data', function (buffer) { responseText += buffer; }); + response.on('end', function () { try { let args = Stimulsoft.Report.Dictionary.StiSqlAdapterService.decodeCommandResult(responseText); @@ -120,29 +130,27 @@ StiHandler.prototype.https = function (data, callback) { callback(args); } catch (e) { - console.log('RequestError: ' + e.message); + console.log('ResponseError: ' + e.message); + console.log(responseText); + process.exit(1); } }); }); request.on('error', function (e) { console.log('RequestError: ' + e.message); - }) + process.exit(1); + }); request.on('timeout', function () { console.log('RequestError: Timeout ' + this.timeout + 'ms'); - }) + process.exit(2); + }); request.write(data); request.end(); } -StiHandler.prototype.getCookie = function (name) { - if (typeof document == 'undefined') return ''; - let matches = document.cookie.match(new RegExp("(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)")); - return matches ? decodeURIComponent(matches[1]) : ''; -} - StiHandler.prototype.setOptions = function () { Stimulsoft.Report.StiOptions.WebServer.timeout = this.timeout; Stimulsoft.Report.StiOptions.WebServer.encryptData = this.encryptData; @@ -185,6 +193,8 @@ function StiHandler() { this.escapeQueryParameters = {escapeQueryParameters}; this.databases = {databases}; this.frameworkType = {framework}; + this.cookie = {cookie}; + this.csrfToken = {csrfToken}; this.setOptions(); } diff --git a/src/classes/StiHandler.php b/src/classes/StiHandler.php index ffaf4c0..40e92a7 100644 --- a/src/classes/StiHandler.php +++ b/src/classes/StiHandler.php @@ -60,6 +60,9 @@ class StiHandler extends StiBaseHandler /** @var bool Enables server-side file name checking for saving the report to eliminate dangerous values. */ public $checkFileNames = true; + /** @var string Contains a string with cookies that will be passed when requesting events. */ + public $cookie = null; + ### Events: Component @@ -316,6 +319,17 @@ private function updateOptions() StiFunctions::populateObject($this, $this->options); } + private function getCsrfToken() + { + if (function_exists('csrf_token')) + return csrf_token(); + + if (array_key_exists('csrftoken', $_COOKIE)) + return $_COOKIE['csrftoken']; + + return null; + } + ### Results @@ -409,12 +423,10 @@ private function getJavaScript() { $result = StiResourcesHelper::getResult('stimulsoft.handler.js'); if ($result->success) { - $csrf_token = function_exists('csrf_token') ? csrf_token() : null; $script = $result->data ?? ''; // Replace Handler parameters $script = str_replace('{databases}', StiFunctions::getJavaScriptValue(StiDatabaseType::getValues()), $script); - $script = str_replace('{csrf_token}', StiFunctions::getJavaScriptValue($csrf_token), $script); $script = str_replace('{url}', StiFunctions::getJavaScriptValue($this->getUrl()), $script); $script = str_replace('{timeout}', StiFunctions::getJavaScriptValue($this->timeout), $script); $script = str_replace('{encryptData}', StiFunctions::getJavaScriptValue($this->encryptData), $script); @@ -422,6 +434,8 @@ private function getJavaScript() $script = str_replace('{checkDataAdaptersVersion}', StiFunctions::getJavaScriptValue($this->checkDataAdaptersVersion), $script); $script = str_replace('{escapeQueryParameters}', StiFunctions::getJavaScriptValue($this->escapeQueryParameters), $script); $script = str_replace('{framework}', StiFunctions::getJavaScriptValue('PHP'), $script); + $script = str_replace('{cookie}', StiFunctions::getJavaScriptValue($this->cookie), $script); + $script = str_replace('{csrfToken}', StiFunctions::getJavaScriptValue($this->getCsrfToken()), $script); if (StiHandler::$legacyMode) $script = str_replace( diff --git a/src/classes/StiNodeJs.php b/src/classes/StiNodeJs.php index 27514af..6e5224a 100644 --- a/src/classes/StiNodeJs.php +++ b/src/classes/StiNodeJs.php @@ -37,6 +37,9 @@ class StiNodeJs /** @var array Full text of the last error as an array of strings. */ public $errorStack; + /** @var bool Enables automatic passing of cookies in HTTP requests. */ + public $passCookies = true; + ### Parameters @@ -108,10 +111,24 @@ private static function getHandlerUrl($url): string { return "$protocol://$host/$url"; } + private function getCookieString() + { + if ($this->passCookies) { + if (array_key_exists('HTTP_COOKIE', $_SERVER)) + return $_SERVER['HTTP_COOKIE']; + + if (count($_COOKIE) > 0) + return http_build_query($_COOKIE, '', '; '); + } + + return null; + } + private function getHandlerScript(): string { $handler = $this->getHandler(); $handler->url = self::getHandlerUrl($handler->getUrl()); + $handler->cookie = $this->getCookieString(); $script = $handler->getHtml(StiHtmlMode::Scripts); return str_replace("Stimulsoft.handler.send", "Stimulsoft.handler.https", $script); } @@ -129,7 +146,7 @@ private function getNodeError($returnError, int $returnCode) { $lines = is_array($returnError) ? $returnError : explode("\n", $returnError ?? ""); $npmError = false; - $errors = ["npm ERR", "Error", "SyntaxError", "ReferenceError", "TypeError", "RequestError"]; + $errors = ["npm ERR", "Error", "SyntaxError", "ReferenceError", "TypeError", "RequestError", "ResponseError"]; foreach ($lines as $line) { if (!StiFunctions::isNullOrEmpty($line)) { foreach ($errors as $error) { @@ -472,10 +489,11 @@ public function run(string $script) $errorText = !StiFunctions::isNullOrEmpty($error) ? $error : $output; $this->error = $this->getNodeError($errorText, $result); - $this->errorStack = $this->getNodeErrorStack($errorText); - if (!StiFunctions::isNullOrEmpty($this->error)) + if (!StiFunctions::isNullOrEmpty($this->error)) { + $this->errorStack = $this->getNodeErrorStack($errorText); return false; + } if (!StiFunctions::isNullOrEmpty($output)) { try { @@ -499,6 +517,7 @@ public function run(string $script) } catch (Exception $e) { $this->error = "ParseError: " . $e->getMessage(); + $this->errorStack = $this->getNodeErrorStack($errorText); return false; } } @@ -518,4 +537,4 @@ public function __construct(StiComponent $component = null) $this->architecture = $this->getArchitecture(); $this->workingDirectory = getcwd(); } -} \ No newline at end of file +}