From e899781cb5e258207805a79afe629cafdb9ebd0a Mon Sep 17 00:00:00 2001 From: yuri Date: Mon, 18 Mar 2019 10:47:59 +0200 Subject: [PATCH] websocket fixes --- application/Espo/Core/Portal/Container.php | 6 ++- .../Espo/Core/defaults/systemConfig.php | 12 +++--- .../Espo/Resources/i18n/en_US/Settings.json | 5 +-- .../Resources/layouts/Settings/settings.json | 11 +---- .../metadata/entityDefs/Settings.json | 9 ---- client/src/views/admin/settings.js | 19 -------- client/src/web-socket-manager.js | 43 +++++++++++++------ websocket.php | 43 +++++++------------ 8 files changed, 60 insertions(+), 88 deletions(-) diff --git a/application/Espo/Core/Portal/Container.php b/application/Espo/Core/Portal/Container.php index 29609da141..6693428e85 100644 --- a/application/Espo/Core/Portal/Container.php +++ b/application/Espo/Core/Portal/Container.php @@ -104,7 +104,7 @@ class Container extends \Espo\Core\Container { $this->set('portal', $portal); - $data = array(); + $data = []; foreach ($this->get('portal')->getSettingsAttributeList() as $attribute) { $data[$attribute] = $this->get('portal')->get($attribute); } @@ -133,6 +133,10 @@ class Container extends \Espo\Core\Container unset($data['defaultCurrency']); } + if ($this->get('config')->get('webSocketInPortalDisabled')) { + $this->get('config')->set('useWebSocket', false); + } + foreach ($data as $attribute => $value) { $this->get('config')->set($attribute, $value, true); } diff --git a/application/Espo/Core/defaults/systemConfig.php b/application/Espo/Core/defaults/systemConfig.php index 68e64b9416..24a6373e5c 100644 --- a/application/Espo/Core/defaults/systemConfig.php +++ b/application/Espo/Core/defaults/systemConfig.php @@ -118,6 +118,12 @@ return [ 'recommendedMariadbParams', 'phpExecutablePath', 'webSocketDebugMode', + 'webSocketSslCertificateFile', + 'webSocketSslCertificateLocalPrivateKey', + 'webSocketSslCertificatePassphrase', + 'webSocketSslAllowSelfSigned', + 'webSocketUseSecureServer', + 'webSocketPort', ], 'adminItems' => [ 'devMode', @@ -187,9 +193,6 @@ return [ 'adminNotificationsNewExtensionVersion', 'leadCaptureAllowOrigin', 'cronDisabled', - 'webSocketSslCertificateFile', - 'webSocketSslCertificateKeyFile', - 'webSocketSslAllowSelfSigned', ], 'superAdminItems' => [ 'jobMaxPortion', @@ -210,9 +213,6 @@ return [ 'webSocketUrl', ], 'superAdminSystemItems' => [ - 'webSocketSslCertificateFile', - 'webSocketSslCertificateKeyFile', - 'webSocketSslAllowSelfSigned', ], 'userItems' => [ 'outboundEmailFromAddress', diff --git a/application/Espo/Resources/i18n/en_US/Settings.json b/application/Espo/Resources/i18n/en_US/Settings.json index f9cd921f25..d8bc1ada0d 100644 --- a/application/Espo/Resources/i18n/en_US/Settings.json +++ b/application/Espo/Resources/i18n/en_US/Settings.json @@ -119,10 +119,7 @@ "daemonProcessTimeout": "Daemon Process Timeout", "cronDisabled": "Disable Cron", "maintenanceMode": "Maintenance Mode", - "useWebSocket": "Use WebSocket", - "webSocketSslAllowSelfSigned": "Allow self-signed SSL certificate", - "webSocketSslCertificateFile": "SSL certificate file", - "webSocketSslCertificateKeyFile": "SSL certificate file path key file" + "useWebSocket": "Use WebSocket" }, "options": { "weekStart": { diff --git a/application/Espo/Resources/layouts/Settings/settings.json b/application/Espo/Resources/layouts/Settings/settings.json index d595e25398..edaf79c16f 100644 --- a/application/Espo/Resources/layouts/Settings/settings.json +++ b/application/Espo/Resources/layouts/Settings/settings.json @@ -4,7 +4,8 @@ "rows": [ [{"name": "useCache"}, {"name": "siteUrl"}], [{"name": "b2cMode"}, {"name": "aclStrictMode"}], - [{"name": "maintenanceMode"}, {"name": "cronDisabled"}] + [{"name": "maintenanceMode"}, {"name": "cronDisabled"}], + [{"name": "useWebSocket"}, false] ] }, { @@ -39,13 +40,5 @@ [{"name": "calendarEntityList"}, {"name": "activitiesEntityList"}], [false, {"name": "historyEntityList"}] ] - }, - { - "label": "WebSocket", - "rows": [ - [{"name": "useWebSocket"}, false], - [{"name": "webSocketSslCertificateFile"}, {"name": "webSocketSslCertificateKeyFile"}], - [{"name": "webSocketSslAllowSelfSigned"}, false] - ] } ] diff --git a/application/Espo/Resources/metadata/entityDefs/Settings.json b/application/Espo/Resources/metadata/entityDefs/Settings.json index 4e41d2d543..ff79024115 100644 --- a/application/Espo/Resources/metadata/entityDefs/Settings.json +++ b/application/Espo/Resources/metadata/entityDefs/Settings.json @@ -555,15 +555,6 @@ }, "useWebSocket": { "type": "bool" - }, - "webSocketSslCertificateFile": { - "type": "varchar" - }, - "webSocketSslCertificateKeyFile": { - "type": "varchar" - }, - "webSocketSslAllowSelfSigned": { - "type": "bool" } } } diff --git a/client/src/views/admin/settings.js b/client/src/views/admin/settings.js index 8d24a52511..af620ef62a 100644 --- a/client/src/views/admin/settings.js +++ b/client/src/views/admin/settings.js @@ -40,25 +40,6 @@ Espo.define('views/admin/settings', 'views/settings/record/edit', function (Dep) this.hideField('maintenanceMode'); this.setFieldReadOnly('useWebSocket'); this.setFieldReadOnly('siteUrl'); - - this.hideField('webSocketSslCertificateFile'); - this.hideField('webSocketSslCertificateKeyFile'); - this.hideField('webSocketSslAllowSelfSigned'); - } else { - this.controlWebSocketFieldsVisibility(); - this.listenTo(this.model, 'change:useWebSocket', this.controlWebSocketFieldsVisibility); - } - }, - - controlWebSocketFieldsVisibility: function () { - if (this.model.get('useWebSocket')) { - this.showField('webSocketSslCertificateFile'); - this.showField('webSocketSslCertificateKeyFile'); - this.showField('webSocketSslAllowSelfSigned'); - } else { - this.hideField('webSocketSslCertificateFile'); - this.hideField('webSocketSslCertificateKeyFile'); - this.hideField('webSocketSslAllowSelfSigned'); } } }); diff --git a/client/src/web-socket-manager.js b/client/src/web-socket-manager.js index c8c6bdcc56..4e2a07b08b 100644 --- a/client/src/web-socket-manager.js +++ b/client/src/web-socket-manager.js @@ -40,9 +40,6 @@ define('web-socket-manager', [], function () { this.url = url.substr(5); this.protocolPart = 'ws://'; } - if (~this.url.indexOf(':')) { - this.port = parseInt(this.url.split(':')[1]); - } } else { var siteUrl = this.config.get('siteUrl') || ''; if (siteUrl.indexOf('https://') === 0) { @@ -53,22 +50,30 @@ define('web-socket-manager', [], function () { this.protocolPart = 'ws://'; } + if (~this.url.indexOf('/')) { - this.url = this.url.substr(0, this.url.indexOf('/')); + this.url = this.url.replace(/\/$/, ''); } - } - if (!this.port) { if (this.protocolPart === 'wss://') { - this.port = 8443; + var port = 443; } else { - this.port = 8080; + var port = 8080; + } + + var si = this.url.indexOf('/'); + if (~si) { + this.url = this.url.substr(0, si) + ':' + port; + } else { + this.url += ':' + port; + } + + if (this.protocolPart == 'wss://') { + this.url += '/wss'; } } - if (~this.url.indexOf(':')) { - this.url = this.url.substr(0, this.url.indexOf(':')); - } + this.subscribeQueue = []; }; _.extend(WebSocketManager.prototype, { @@ -78,12 +83,18 @@ define('web-socket-manager', [], function () { var authArray = Base64.decode(auth).split(':'); var username = authArray[0]; var authToken = authArray[1]; - var url = this.protocolPart + this.url + ':' + this.port; + var url = this.protocolPart + this.url; url += '?authToken=' + authToken + '&userId=' + userId; var connection = this.connection = new ab.Session(url, - function () {}, + function () { + this.subscribeQueue.forEach(function (item) { + this.subscribe(item.category, item.callback); + }, this); + this.subscribeQueue = []; + this.isConnected = true; + }.bind(this), function () {}, {'skipSubprotocolCheck': true} ); @@ -95,6 +106,10 @@ define('web-socket-manager', [], function () { subscribe: function (category, callback) { if (!this.connection) return; + if (!this.isConnected) { + this.subscribeQueue.push({category: category, callback: callback}); + return; + } try { this.connection.subscribe(category, callback); } catch (e) { @@ -126,6 +141,8 @@ define('web-socket-manager', [], function () { } catch (e) { console.error(e.message); } + + this.isConnected = false; }, }); diff --git a/websocket.php b/websocket.php index 086c4543f0..8e023f2db3 100644 --- a/websocket.php +++ b/websocket.php @@ -48,39 +48,28 @@ $pull->bind('tcp://127.0.0.1:5555'); $pull->on('message', [$pusher, 'onMessageReceive']); -$useSsl = false; -$port = null; - -$webSocketUrl = $config->get('webSocketUrl'); -if ($webSocketUrl) { - if (stripos($webSocketUrl, 'wss://') === 0) { - $useSsl = true; - } - $port = parse_url($webSocketUrl, \PHP_URL_PORT); -} else { - $siteUrl = $config->get('siteUrl'); - if ($siteUrl && stripos($siteUrl, 'https://') === 0) { - $useSsl = true; - } -} +$useSecureServer = $config->get('webSocketUseSecureServer'); +$port = $config->get('webSocketPort'); if (!$port) { - $port = $useSsl ? '8443' : '8080'; + $port = $useSecureServer ? '8443' : '8080'; } $webSocket = new \React\Socket\Server('0.0.0.0:'.$port, $loop); -if ($useSsl) { - $webSocket = new \React\Socket\SecureServer( - $webSocket, - $loop, - [ - 'local_cert' => $config->get('webSocketSslCertificateFile'), - 'local_pk' => $config->get('webSocketSslCertificateKeyFile'), - 'allow_self_signed' => $config->get('webSocketSslAllowSelfSigned', false), - 'verify_peer' => false, - ] - ); +if ($useSecureServer) { + $sslParams = [ + 'local_cert' => $config->get('webSocketSslCertificateFile'), + 'allow_self_signed' => $config->get('webSocketSslAllowSelfSigned', false), + 'verify_peer' => false, + ]; + if ($config->get('webSocketSslCertificatePassphrase')) { + $sslParams['passphrase'] = $config->get('webSocketSslCertificatePassphrase'); + } + if ($config->get('webSocketSslCertificateLocalPrivateKey')) { + $sslParams['local_pk'] = $config->get('webSocketSslCertificateLocalPrivateKey'); + } + $webSocket = new \React\Socket\SecureServer($webSocket, $loop, $sslParams); } $webServer = new \Ratchet\Server\IoServer(