From f9164adee885f8591c2dabdb159f08f0b07f8e30 Mon Sep 17 00:00:00 2001 From: GermanBluefox Date: Mon, 31 Jan 2022 22:48:42 +0100 Subject: [PATCH] * (bluefox) Update socket.io library to 2.4.1 * (bluefox) Used json config for settings --- .releaseconfig.json | 5 +- README.md | 14 +- admin/i18n/de/translations.json | 20 ++ admin/i18n/en/translations.json | 20 ++ admin/i18n/es/translations.json | 20 ++ admin/i18n/fr/translations.json | 20 ++ admin/i18n/it/translations.json | 20 ++ admin/i18n/nl/translations.json | 20 ++ admin/i18n/pl/translations.json | 20 ++ admin/i18n/pt/translations.json | 20 ++ admin/i18n/ru/translations.json | 20 ++ admin/i18n/zh-cn/translations.json | 20 ++ admin/index.html | 159 ------------- admin/index_m.html | 202 ----------------- admin/jsonConfig.json | 160 +++++++++++++ admin/words.js | 22 -- gulpfile.js | 22 +- io-package.json | 10 +- lib/passportSocket.js | 81 ------- lib/socket.io.js | 9 + lib/socket.js | 351 ++++++++++++++--------------- lib/ws.js | 343 ---------------------------- main.js | 1 - package.json | 8 +- 24 files changed, 572 insertions(+), 1015 deletions(-) create mode 100644 admin/i18n/de/translations.json create mode 100644 admin/i18n/en/translations.json create mode 100644 admin/i18n/es/translations.json create mode 100644 admin/i18n/fr/translations.json create mode 100644 admin/i18n/it/translations.json create mode 100644 admin/i18n/nl/translations.json create mode 100644 admin/i18n/pl/translations.json create mode 100644 admin/i18n/pt/translations.json create mode 100644 admin/i18n/ru/translations.json create mode 100644 admin/i18n/zh-cn/translations.json delete mode 100644 admin/index.html delete mode 100644 admin/index_m.html create mode 100644 admin/jsonConfig.json delete mode 100644 admin/words.js delete mode 100644 lib/passportSocket.js create mode 100644 lib/socket.io.js delete mode 100644 lib/ws.js diff --git a/.releaseconfig.json b/.releaseconfig.json index 6f9d0f5..3ce9936 100644 --- a/.releaseconfig.json +++ b/.releaseconfig.json @@ -1,3 +1,6 @@ { - "plugins": ["iobroker", "license"] + "plugins": ["iobroker", "license"], + "exec": { + "before_commit": "npm run build" + } } diff --git a/README.md b/README.md index 6d06089..ee4c008 100644 --- a/README.md +++ b/README.md @@ -311,17 +311,9 @@ You can set option *Force Web-Sockets* to force using only web-sockets transport --> ## Changelog -### 4.0.3 (2022-01-30) -* (bluefox) Removed the deprecated "passport.socketio" packet - -### 4.0.2 (2022-01-30) -* (bluefox) Removed "force web sockets" option - -### 4.0.1 (2022-01-29) -* (bluefox) Fixed authentication - -### 4.0.0 (2022-01-29) -* (bluefox) Remove socket-io and use only web sockets +### __WORK IN PROGRESS__ +* (bluefox) Update socket.io library to 2.4.1 +* (bluefox) Used json config for settings ### 3.1.5 (2021-10-22) * (foxriver76) make error logging on failed authentication more specific diff --git a/admin/i18n/de/translations.json b/admin/i18n/de/translations.json new file mode 100644 index 0000000..bacd89d --- /dev/null +++ b/admin/i18n/de/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Laufen unter Anwender", + "IP": "IP", + "Port": "Port", + "Secure(HTTPS)": "Verschlüsselung(HTTPS)", + "Authentication": "Authentifizierung", + "Listen on all IPs": "An allen IP Adressen hören", + "help_tip": "Beim Speichern von Einstellungen der Adapter wird sofort neu gestartet.", + "Public certificate": "Publikzertifikat", + "Private certificate": "Privatzertifikat", + "Chained certificate": "Kettenzertifikat", + "Let's Encrypt settings": "Einstellungen Let's Encrypt", + "Use Lets Encrypt certificates": "Benutzen Let's Encrypt Zertifikate", + "Use this instance for automatic update": "Benutze diese Instanz für automatische Updates", + "Port to check the domain": "Port um die Domain zu prüfen", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Lesen Sie mehr über Let's Encrypt-Zertifikate", + "Undo": "Rückgängig", + "Force Web-Sockets": "Web-Sockets erzwingen" +} \ No newline at end of file diff --git a/admin/i18n/en/translations.json b/admin/i18n/en/translations.json new file mode 100644 index 0000000..22be381 --- /dev/null +++ b/admin/i18n/en/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Run as", + "IP": "IP", + "Port": "Port", + "Secure(HTTPS)": "Secure(HTTPS)", + "Authentication": "Authentication", + "Listen on all IPs": "Listen on all IPs", + "help_tip": "On save the adapter restarts with new configuration immediately", + "Public certificate": "Public certificate", + "Private certificate": "Private certificate", + "Chained certificate": "Chained certificate", + "Let's Encrypt settings": "Let's Encrypt settings", + "Use Lets Encrypt certificates": "Use Let's Encrypt certificates", + "Use this instance for automatic update": "Use this instance for automatic update", + "Port to check the domain": "Port to check the domain", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Read about Let's Encrypt certificates", + "Undo": "Undo", + "Force Web-Sockets": "Force Web-Sockets" +} \ No newline at end of file diff --git a/admin/i18n/es/translations.json b/admin/i18n/es/translations.json new file mode 100644 index 0000000..3c438fa --- /dev/null +++ b/admin/i18n/es/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Correr como", + "IP": "IP", + "Port": "Puerto", + "Secure(HTTPS)": "Seguro (HTTPS)", + "Authentication": "Autenticación", + "Listen on all IPs": "Escuchar en todas las direcciones IP", + "help_tip": "Al guardar, el adaptador se reinicia con una nueva configuración de inmediato", + "Public certificate": "Certificado público", + "Private certificate": "Certificado privado", + "Chained certificate": "Certificado encadenado", + "Let's Encrypt settings": "Vamos a cifrar la configuración", + "Use Lets Encrypt certificates": "Utilice los certificados Let's Encrypt", + "Use this instance for automatic update": "Use esta instancia para la actualización automática", + "Port to check the domain": "Puerto para verificar el dominio", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Lea acerca de los certificados de Let's Encrypt", + "Undo": "Deshacer", + "Force Web-Sockets": "Forzar Web-Sockets" +} \ No newline at end of file diff --git a/admin/i18n/fr/translations.json b/admin/i18n/fr/translations.json new file mode 100644 index 0000000..4c4e6c6 --- /dev/null +++ b/admin/i18n/fr/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Courir comme", + "IP": "IP", + "Port": "Port", + "Secure(HTTPS)": "Sécurisé (HTTPS)", + "Authentication": "Authentification", + "Listen on all IPs": "Écoutez sur toutes les adresses IP", + "help_tip": "Sur enregistrer l'adaptateur redémarre avec la nouvelle configuration immédiatement", + "Public certificate": "Certificat public", + "Private certificate": "Certificat privé", + "Chained certificate": "Certificat chaîné", + "Let's Encrypt settings": "Cryptons les paramètres", + "Use Lets Encrypt certificates": "Utiliser les certificats Let's Encrypt", + "Use this instance for automatic update": "Utilisez cette instance pour la mise à jour automatique", + "Port to check the domain": "Port pour vérifier le domaine", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "En savoir plus sur les certificats Let's Encrypt", + "Undo": "annuler", + "Force Web-Sockets": "Forcer les Web-Sockets" +} \ No newline at end of file diff --git a/admin/i18n/it/translations.json b/admin/i18n/it/translations.json new file mode 100644 index 0000000..a2ad8dd --- /dev/null +++ b/admin/i18n/it/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Correre come", + "IP": "IP", + "Port": "Porta", + "Secure(HTTPS)": "Sicuro (HTTPS)", + "Authentication": "Autenticazione", + "Listen on all IPs": "Ascolta su tutti gli IP", + "help_tip": "Al salvataggio, l'adattatore si riavvia immediatamente con la nuova configurazione", + "Public certificate": "Certificato pubblico", + "Private certificate": "Certificato privato", + "Chained certificate": "Certificato incatenato", + "Let's Encrypt settings": "Let's Encrypt settings", + "Use Lets Encrypt certificates": "Utilizza Let's Encrypt certificates", + "Use this instance for automatic update": "Utilizza questa istanza per l'aggiornamento automatico", + "Port to check the domain": "Porta per controllare il dominio", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Leggi i certificati Let's Encrypt", + "Undo": "Annullare", + "Force Web-Sockets": "Forza Web-Socket" +} \ No newline at end of file diff --git a/admin/i18n/nl/translations.json b/admin/i18n/nl/translations.json new file mode 100644 index 0000000..73fb978 --- /dev/null +++ b/admin/i18n/nl/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Rennen als", + "IP": "IK P", + "Port": "Haven", + "Secure(HTTPS)": "Secure (HTTPS)", + "Authentication": "authenticatie", + "Listen on all IPs": "Luister op alle IP's", + "help_tip": "Bij opslaan wordt de adapter onmiddellijk opnieuw opgestart met een nieuwe configuratie", + "Public certificate": "Openbaar certificaat", + "Private certificate": "Privé certificaat", + "Chained certificate": "Geketend certificaat", + "Let's Encrypt settings": "Laten we de instellingen versleutelen", + "Use Lets Encrypt certificates": "Gebruik Let's Encrypt-certificaten", + "Use this instance for automatic update": "Gebruik deze instantie voor automatische update", + "Port to check the domain": "Poort om het domein te controleren", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Lees over Let's Encrypt-certificaten", + "Undo": "ongedaan maken", + "Force Web-Sockets": "Forceer web-sockets" +} \ No newline at end of file diff --git a/admin/i18n/pl/translations.json b/admin/i18n/pl/translations.json new file mode 100644 index 0000000..59dfda8 --- /dev/null +++ b/admin/i18n/pl/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Uruchom jako", + "IP": "IP", + "Port": "Port", + "Secure(HTTPS)": "Bezpieczne (HTTPS)", + "Authentication": "Uwierzytelnianie", + "Listen on all IPs": "Posłuchaj na wszystkich IP", + "help_tip": "Po zapisaniu adapter natychmiast uruchamia się ponownie z nową konfiguracją", + "Public certificate": "Certyfikat publiczny", + "Private certificate": "Prywatny certyfikat", + "Chained certificate": "Przykuty certyfikat", + "Let's Encrypt settings": "Zakodujmy ustawienia", + "Use Lets Encrypt certificates": "Użyj Let's Encrypt certificates", + "Use this instance for automatic update": "Użyj tej instancji do automatycznej aktualizacji", + "Port to check the domain": "Port do sprawdzenia domeny", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Przeczytaj o certyfikatach Let's Encrypt", + "Undo": "Cofnij", + "Force Web-Sockets": "Wymuś gniazda sieciowe" +} \ No newline at end of file diff --git a/admin/i18n/pt/translations.json b/admin/i18n/pt/translations.json new file mode 100644 index 0000000..d16d308 --- /dev/null +++ b/admin/i18n/pt/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Correr como", + "IP": "IP", + "Port": "Porta", + "Secure(HTTPS)": "Seguro (HTTPS)", + "Authentication": "Autenticação", + "Listen on all IPs": "Ouça todos os IPs", + "help_tip": "Em salvar, o adaptador reinicia com a nova configuração imediatamente", + "Public certificate": "Certificado público", + "Private certificate": "Certificado privado", + "Chained certificate": "Certificado acorrentado", + "Let's Encrypt settings": "Vamos criptografar configurações", + "Use Lets Encrypt certificates": "Use Vamos criptografar certificados", + "Use this instance for automatic update": "Use esta instância para atualização automática", + "Port to check the domain": "Porta para verificar o domínio", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Leia sobre os certificados Let's Encrypt", + "Undo": "Desfazer", + "Force Web-Sockets": "Forçar Web-Sockets" +} \ No newline at end of file diff --git a/admin/i18n/ru/translations.json b/admin/i18n/ru/translations.json new file mode 100644 index 0000000..fe5181f --- /dev/null +++ b/admin/i18n/ru/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "Запустить от пользователя", + "IP": "IP", + "Port": "Порт", + "Secure(HTTPS)": "Шифрование(HTTPS)", + "Authentication": "Аутентификация", + "Listen on all IPs": "Открыть сокет на всех IP адресах", + "help_tip": "Сразу после сохранения настроек драйвер перезапуститься с новыми значениями", + "Public certificate": "'Public' сертификат", + "Private certificate": "'Private' сертификат", + "Chained certificate": "'Chained' сертификат", + "Let's Encrypt settings": "Настройки Let's Encrypt", + "Use Lets Encrypt certificates": "Использовать сертификаты Let's Encrypt", + "Use this instance for automatic update": "Обновлять сертификаты в этом драйвере", + "Port to check the domain": "Порт для проверки доменного имени", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "Читать о сертификатах Let's Encrypt", + "Undo": "Отменить", + "Force Web-Sockets": "Использовать только веб-сокеты" +} \ No newline at end of file diff --git a/admin/i18n/zh-cn/translations.json b/admin/i18n/zh-cn/translations.json new file mode 100644 index 0000000..27ad2a2 --- /dev/null +++ b/admin/i18n/zh-cn/translations.json @@ -0,0 +1,20 @@ +{ + "Run as": "运行方式", + "IP": "知识产权", + "Port": "港口", + "Secure(HTTPS)": "安全(HTTPS)", + "Authentication": "验证", + "Listen on all IPs": "监听所有 IP", + "help_tip": "保存后适配器立即使用新配置重新启动", + "Public certificate": "公共证书", + "Private certificate": "私人证书", + "Chained certificate": "链式证书", + "Let's Encrypt settings": "让我们加密设置", + "Use Lets Encrypt certificates": "使用 Let's Encrypt 证书", + "Use this instance for automatic update": "使用此实例进行自动更新", + "Port to check the domain": "检查域的端口", + "Let's Encrypt SSL": "Let's Encrypt SSL", + "Read about Let's Encrypt certificates": "阅读 Let's Encrypt 证书", + "Undo": "撤消", + "Force Web-Sockets": "强制 Web 套接字" +} \ No newline at end of file diff --git a/admin/index.html b/admin/index.html deleted file mode 100644 index 7a9aee0..0000000 --- a/admin/index.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - -
- -

socket.io adapter settings

- - - - - - - - - - - - - - - - - - - - - - - - - -
 

Let's Encrypt settings

-
- - diff --git a/admin/index_m.html b/admin/index_m.html deleted file mode 100644 index 54c549d..0000000 --- a/admin/index_m.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - - - - - - - - - - - -
-
- -
-
-
- -
-
-
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
-
-
-
-
- logo -
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
-
- - diff --git a/admin/jsonConfig.json b/admin/jsonConfig.json new file mode 100644 index 0000000..aef5e2c --- /dev/null +++ b/admin/jsonConfig.json @@ -0,0 +1,160 @@ +{ + "type": "tabs", + "i18n": true, + "items": { + "mainTab": { + "type": "panel", + "label": "Main settings", + "items": { + "bind": { + "type": "ip", + "listenOnAllPorts": true, + "label": "IP", + "sm": 12, + "md": 8, + "lg": 5 + }, + "port": { + "type": "number", + "min": 1, + "max": 65565, + "label": "Port", + "sm": 12, + "md": 4, + "lg": 3 + }, + "secure": { + "newLine": true, + "type": "checkbox", + "label": "Secure(HTTPS)", + "sm": 12, + "md": 6, + "lg": 2 + }, + "certPublic": { + "type": "certificate", + "hidden": "!data.secure", + "certType": "public", + "validator": "!data.secure || data.certPublic", + "label": "Public certificate", + "sm": 12, + "md": 6, + "lg": 2 + }, + "certPrivate": { + "hidden": "!data.secure", + "type": "certificate", + "certType": "private", + "validator": "!data.secure || data.certPrivate", + "label": "Private certificate", + "sm": 12, + "md": 6, + "lg": 2 + }, + "certChained": { + "hidden": "!data.secure", + "type": "certificate", + "certType": "chained", + "label": "Chained certificate", + "sm": 12, + "md": 6, + "lg": 2 + }, + "auth": { + "newLine": true, + "type": "checkbox", + "confirm": { + "condition": "!data.secure && data.auth", + "title": "Warning!", + "text": "Unsecure_Auth", + "ok": "Ignore warning", + "cancel": "Disable authentication", + "type": "warning", + "alsoDependsOn": [ + "secure" + ] + }, + "label": "Authentication", + "sm": 12, + "md": 6, + "lg": 2 + }, + "defaultUser": { + "hidden": "!!data.auth", + "type": "user", + "label": "Run as", + "sm": 12, + "md": 6, + "lg": 2 + }, + "ttl": { + "hidden": "!data.auth", + "type": "number", + "label": "Login timeout", + "help": "sec", + "sm": 12, + "md": 6, + "lg": 2 + }, + "forceWebSockets": { + "newLine": true, + "type": "checkbox", + "label": "Force Web-Sockets", + "sm": 12, + "md": 6, + "lg": 2 + } + } + }, + "leTab": { + "type": "panel", + "label": "Let's Encrypt SSL", + "disabled": "!data.secure", + "items": { + "_image": { + "type": "staticImage", + "tooltip": "Read about Let's Encrypt certificates", + "href": "https://github.com/ioBroker/ioBroker.admin/blob/master/README.md#lets-encrypt-certificates", + "src": "../../img/le.png", + "style": { + "width": 200, + "height": 59 + } + }, + "_link": { + "newLine": true, + "type": "staticLink", + "href": "https://github.com/ioBroker/ioBroker.admin/blob/master/README.md#lets-encrypt-certificates", + "label": "Read about Let's Encrypt certificates", + "style": { + "fontSize": 16, + "marginBottom": 20 + } + }, + "leEnabled": { + "newLine": true, + "type": "checkbox", + "label": "Use Lets Encrypt certificates" + }, + "leUpdate": { + "newLine": true, + "type": "checkbox", + "hidden": "!data.leEnabled", + "label": "Use this instance for automatic update" + }, + "lePort": { + "newLine": true, + "sm": 11, + "lg": 4, + "type": "number", + "hidden": "!data.leEnabled || !data.leUpdate", + "label": "Port to check the domain", + "style": { + "marginTop": 15, + "maxWidth": 200 + } + } + } + } + } +} \ No newline at end of file diff --git a/admin/words.js b/admin/words.js deleted file mode 100644 index 9fe5f7b..0000000 --- a/admin/words.js +++ /dev/null @@ -1,22 +0,0 @@ -// DO NOT EDIT THIS FILE!!! IT WILL BE AUTOMATICALLY GENERATED FROM src/i18n -/*global systemDictionary:true */ -'use strict'; - -systemDictionary = { - "socket.io adapter settings": { "en": "socket.io adapter settings", "de": "socket.io adapter settings", "ru": "socket.io adapter settings", "pt": "Configurações do adaptador socket.io", "nl": "socket.io-adapterinstellingen", "fr": "Paramètres de l'adaptateur socket.io", "it": "impostazioni della scheda socket.io", "es": "Configuración del adaptador socket.io", "pl": "ustawienia adaptera socket.io"}, - "Run as:": { "en": "Run as", "de": "Laufen unter Anwender", "ru": "Запустить от пользователя", "pt": "Correr como", "nl": "Rennen als", "fr": "Courir comme", "it": "Correre come", "es": "Correr como", "pl": "Uruchom jako"}, - "IP:": { "en": "IP", "de": "IP", "ru": "IP", "pt": "IP", "nl": "IK P", "fr": "IP", "it": "IP", "es": "IP", "pl": "IP"}, - "Port:": { "en": "Port", "de": "Port", "ru": "Порт", "pt": "Porta", "nl": "Haven", "fr": "Port", "it": "Porta", "es": "Puerto", "pl": "Port"}, - "Secure(HTTPS):": { "en": "Secure(HTTPS)", "de": "Verschlüsselung(HTTPS)", "ru": "Шифрование(HTTPS)", "pt": "Seguro (HTTPS)", "nl": "Secure (HTTPS)", "fr": "Sécurisé (HTTPS)", "it": "Sicuro (HTTPS)", "es": "Seguro (HTTPS)", "pl": "Bezpieczne (HTTPS)"}, - "Authentication:": { "en": "Authentication", "de": "Authentifikation", "ru": "Аутентификация", "pt": "Autenticação", "nl": "authenticatie", "fr": "Authentification", "it": "Autenticazione", "es": "Autenticación", "pl": "Poświadczenie"}, - "Listen on all IPs": { "en": "Listen on all IPs", "de": "An allen IP Adressen hören", "ru": "Открыть сокет на всех IP адресах", "pt": "Ouça todos os IPs", "nl": "Luister op alle IP's", "fr": "Écoutez sur toutes les adresses IP", "it": "Ascolta su tutti gli IP", "es": "Escuchar en todas las direcciones IP", "pl": "Posłuchaj na wszystkich IP"}, - "help_tip": { "en": "On save the adapter restarts with new configuration immediately", "de": "Beim Speichern von Einstellungen der Adapter wird sofort neu gestartet.", "ru": "Сразу после сохранения настроек драйвер перезапуститься с новыми значениями", "pt": "Em salvar, o adaptador reinicia com a nova configuração imediatamente", "nl": "Bij opslaan wordt de adapter onmiddellijk opnieuw opgestart met een nieuwe configuratie", "fr": "Sur enregistrer l'adaptateur redémarre avec la nouvelle configuration immédiatement", "it": "Al salvataggio, l'adattatore si riavvia immediatamente con la nuova configurazione", "es": "Al guardar, el adaptador se reinicia con una nueva configuración de inmediato", "pl": "Po zapisaniu adapter natychmiast uruchamia się ponownie z nową konfiguracją"}, - "Public certificate:": { "en": "Public certificate", "de": "Publikzertifikat", "ru": "'Public' сертификат", "pt": "Certificado público", "nl": "Openbaar certificaat", "fr": "Certificat public", "it": "Certificato pubblico", "es": "Certificado público", "pl": "Certyfikat publiczny"}, - "Private certificate:": { "en": "Private certificate", "de": "Privatzertifikat", "ru": "'Private' сертификат", "pt": "Certificado privado", "nl": "Privé certificaat", "fr": "Certificat privé", "it": "Certificato privato", "es": "Certificado privado", "pl": "Prywatny certyfikat"}, - "Chained certificate:": { "en": "Chained certificate", "de": "Kettenzertifikat", "ru": "'Chained' сертификат", "pt": "Certificado acorrentado", "nl": "Geketend certificaat", "fr": "Certificat chaîné", "it": "Certificato incatenato", "es": "Certificado encadenado", "pl": "Przykuty certyfikat"}, - "Force Web-Sockets:": { "en": "Force Web-Sockets", "de": "Nur Web-Sockets", "ru": "Только Web-Sockets", "pt": "Forçar Web-Sockets", "nl": "Force Web-Sockets", "fr": "Forcer les Web-Sockets", "it": "Force Web-Sockets", "es": "Force Web-Sockets", "pl": "Wymuszaj gniazda internetowe"}, - "Let's Encrypt settings": { "en": "Let's Encrypt settings", "de": "Einstellungen Let's Encrypt", "ru": "Настройки Let's Encrypt", "pt": "Vamos criptografar configurações", "nl": "Laten we de instellingen versleutelen", "fr": "Cryptons les paramètres", "it": "Let's Encrypt settings", "es": "Vamos a cifrar la configuración", "pl": "Zakodujmy ustawienia"}, - "Use Lets Encrypt certificates:": { "en": "Use Let's Encrypt certificates", "de": "Benutzen Let's Encrypt Zertifikate", "ru": "Использовать сертификаты Let's Encrypt", "pt": "Use Vamos criptografar certificados", "nl": "Gebruik Let's Encrypt-certificaten", "fr": "Utiliser les certificats Let's Encrypt", "it": "Utilizza Let's Encrypt certificates", "es": "Utilice los certificados Let's Encrypt", "pl": "Użyj Let's Encrypt certificates"}, - "Use this instance for automatic update:": { "en": "Use this instance for automatic update", "de": "Benutze diese Instanz für automatische Updates", "ru": "Обновлять сертификаты в этом драйвере", "pt": "Use esta instância para atualização automática", "nl": "Gebruik deze instantie voor automatische update", "fr": "Utilisez cette instance pour la mise à jour automatique", "it": "Utilizza questa istanza per l'aggiornamento automatico", "es": "Use esta instancia para la actualización automática", "pl": "Użyj tej instancji do automatycznej aktualizacji"}, - "Port to check the domain:": { "en": "Port to check the domain", "de": "Port um die Domain zu prüfen", "ru": "Порт для проверки доменного имени", "pt": "Porta para verificar o domínio", "nl": "Poort om het domein te controleren", "fr": "Port pour vérifier le domaine", "it": "Porta per controllare il dominio", "es": "Puerto para verificar el dominio", "pl": "Port do sprawdzenia domeny"} -}; \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 2d4ea23..264c457 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -143,7 +143,9 @@ function words2languages(src) { fs.mkdirSync(src + 'i18n/'); } for (const l in langs) { - if (!langs.hasOwnProperty(l)) continue; + if (!langs.hasOwnProperty(l)) { + continue; + } const keys = Object.keys(langs[l]); //keys.sort(); const obj = {}; @@ -182,7 +184,9 @@ function words2languagesFlat(src) { const keys = Object.keys(langs.en); //keys.sort(); for (const l in langs) { - if (!langs.hasOwnProperty(l)) continue; + if (!langs.hasOwnProperty(l)) { + continue; + } const obj = {}; for (let k = 0; k < keys.length; k++) { obj[keys[k]] = langs[l][keys[k]]; @@ -398,4 +402,16 @@ gulp.task('updateReadme', done => { done(); }); -gulp.task('default', gulp.series('updatePackages', 'updateReadme')); \ No newline at end of file +gulp.task('copySocketIo', done => { + let socket = require.resolve('socket.io-client').replace(/\\/g, '/'); + // node_modules/socket.io-client/build/cjs/index.js + const parts = socket.split('/'); + parts.pop(); + parts.pop(); + parts.push('dist'); + parts.push('socket.io.js'); + fs.writeFileSync(__dirname + '/lib/socket.io.js', fs.readFileSync(parts.join('/'))); + done(); +}); + +gulp.task('default', gulp.series('copySocketIo')); \ No newline at end of file diff --git a/io-package.json b/io-package.json index c8dd9d9..f918d2f 100644 --- a/io-package.json +++ b/io-package.json @@ -122,14 +122,21 @@ "extIcon": "https://raw.githubusercontent.com/ioBroker/ioBroker.socketio/master/admin/socketio.png", "type": "communication", "stopBeforeUpdate": true, - "materialize": true, "compact": true, "stopTimeout": 5000, + "adminUI": { + "config": "json" + }, "dependencies": [ { "js-controller": ">=2.0.0" } ], + "globalDependencies": [ + { + "admin": ">=5.0.0" + } + ], "restartAdapters": [ "web" ], @@ -149,6 +156,7 @@ "certPrivate": "", "certChained": "", "defaultUser": "admin", + "forceWebSockets": false, "leEnabled": false, "leUpdate": false, "leCheckPort": 80 diff --git a/lib/passportSocket.js b/lib/passportSocket.js deleted file mode 100644 index c2ae47c..0000000 --- a/lib/passportSocket.js +++ /dev/null @@ -1,81 +0,0 @@ -// Originally taken from here: https://github.com/jfromaniello/passport.socketio/blob/master/lib/index.js -// Copyright Licensed under the MIT-License. 2012-2013 José F. Romaniello. - -function parseCookie(auth, cookieHeader) { - const cookieParser = auth.cookieParser(auth.secret); - const req = { - headers: { - cookie: cookieHeader - } - }; - - let result; - - cookieParser(req, {}, err => { - if (err) { - throw err; - } - result = req.signedCookies || req.cookies; - }); - - return result; -} - -function authorize(options) { - const defaults = { - key: 'connect.sid', - secret: null, - store: null, - userProperty: 'user' - }; - - const auth = Object.assign({}, defaults, options); - - if (!auth.passport) { - throw new Error('passport is required to use require(\'passport\'), please install passport'); - } - - if (!auth.cookieParser) { - throw new Error('cookieParser is required use require(\'cookie-parser\'), connect.cookieParser or express.cookieParser'); - } - - return function (data, accept) { - data.cookie = parseCookie(auth, data.headers.cookie || ''); - data.sessionID = data.cookie[auth.key] || ''; - data[auth.userProperty] = { - logged_in: false - }; - - auth.store.get(data.sessionID, (err, session) => { - if (err) { - return auth.fail(data, 'Error in session store:\n' + err.message, true, accept); - } else - if (!session) { - return auth.fail(data, 'No session found', false, accept); - } else - if (!session[auth.passport._key]) { - return auth.fail(data, 'Passport was not initialized', true, accept); - } - - const userKey = session[auth.passport._key].user; - - if (typeof userKey === 'undefined') { - return auth.fail(data, 'User not authorized through passport. (User Property not found)', false, accept); - } - - auth.passport.deserializeUser(userKey, data, (err, user) => { - if (err) { - return auth.fail(data, err, true, accept); - } else - if (!user) { - return auth.fail(data, 'User not found', false, accept); - } - data[auth.userProperty] = user; - data[auth.userProperty].logged_in = true; - auth.success(data, accept); - }); - }); - }; -} - -exports.authorize = authorize; \ No newline at end of file diff --git a/lib/socket.io.js b/lib/socket.io.js new file mode 100644 index 0000000..50e33f6 --- /dev/null +++ b/lib/socket.io.js @@ -0,0 +1,9 @@ +/*! + * Socket.IO v2.4.0 + * (c) 2014-2021 Guillermo Rauch + * Released under the MIT License. + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.io=e():t.io=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){function r(t,e){"object"==typeof t&&(e=t,t=void 0),e=e||{};var n,r=o(t),i=r.source,p=r.id,u=r.path,h=c[p]&&u in c[p].nsps,f=e.forceNew||e["force new connection"]||!1===e.multiplex||h;return f?(a("ignoring socket cache for %s",i),n=s(i,e)):(c[p]||(a("new io instance for %s",i),c[p]=s(i,e)),n=c[p]),r.query&&!e.query&&(e.query=r.query),n.socket(r.path,e)}var o=n(1),i=n(7),s=n(12),a=n(3)("socket.io-client");t.exports=e=r;var c=e.managers={};e.protocol=i.protocol,e.connect=r,e.Manager=n(12),e.Socket=n(37)},function(t,e,n){function r(t,e){var n=t;e=e||"undefined"!=typeof location&&location,null==t&&(t=e.protocol+"//"+e.host),"string"==typeof t&&("/"===t.charAt(0)&&(t="/"===t.charAt(1)?e.protocol+t:e.host+t),/^(https?|wss?):\/\//.test(t)||(i("protocol-less url %s",t),t="undefined"!=typeof e?e.protocol+"//"+t:"https://"+t),i("parse %s",t),n=o(t)),n.port||(/^(http|ws)$/.test(n.protocol)?n.port="80":/^(http|ws)s$/.test(n.protocol)&&(n.port="443")),n.path=n.path||"/";var r=n.host.indexOf(":")!==-1,s=r?"["+n.host+"]":n.host;return n.id=n.protocol+"://"+s+":"+n.port,n.href=n.protocol+"://"+s+(e&&e.port===n.port?"":":"+n.port),n}var o=n(2),i=n(3)("socket.io-client:url");t.exports=r},function(t,e){function n(t,e){var n=/\/{2,9}/g,r=e.replace(n,"/").split("/");return"/"!=e.substr(0,1)&&0!==e.length||r.splice(0,1),"/"==e.substr(e.length-1,1)&&r.splice(r.length-1,1),r}function r(t,e){var n={};return e.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(t,e,r){e&&(n[e]=r)}),n}var o=/^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,i=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];t.exports=function(t){var e=t,s=t.indexOf("["),a=t.indexOf("]");s!=-1&&a!=-1&&(t=t.substring(0,s)+t.substring(s,a).replace(/:/g,";")+t.substring(a,t.length));for(var c=o.exec(t||""),p={},u=14;u--;)p[i[u]]=c[u]||"";return s!=-1&&a!=-1&&(p.source=e,p.host=p.host.substring(1,p.host.length-1).replace(/;/g,":"),p.authority=p.authority.replace("[","").replace("]","").replace(/;/g,":"),p.ipv6uri=!0),p.pathNames=n(p,p.path),p.queryKey=r(p,p.query),p}},function(t,e,n){(function(r){"use strict";function o(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function i(t){var n=this.useColors;if(t[0]=(n?"%c":"")+this.namespace+(n?" %c":" ")+t[0]+(n?"%c ":" ")+"+"+e.humanize(this.diff),n){var r="color: "+this.color;t.splice(1,0,r,"color: inherit");var o=0,i=0;t[0].replace(/%[a-zA-Z%]/g,function(t){"%%"!==t&&(o++,"%c"===t&&(i=o))}),t.splice(i,0,r)}}function s(){return"object"===("undefined"==typeof console?"undefined":u(console))&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(t){try{null==t?e.storage.removeItem("debug"):e.storage.debug=t}catch(n){}}function c(){var t;try{t=e.storage.debug}catch(n){}return!t&&"undefined"!=typeof r&&"env"in r&&(t=r.env.DEBUG),t}function p(){try{return window.localStorage}catch(t){}}var u="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};e=t.exports=n(5),e.log=s,e.formatArgs=i,e.save=a,e.load=c,e.useColors=o,e.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:p(),e.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],e.formatters.j=function(t){try{return JSON.stringify(t)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},e.enable(c())}).call(e,n(4))},function(t,e){function n(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function o(t){if(u===setTimeout)return setTimeout(t,0);if((u===n||!u)&&setTimeout)return u=setTimeout,setTimeout(t,0);try{return u(t,0)}catch(e){try{return u.call(null,t,0)}catch(e){return u.call(this,t,0)}}}function i(t){if(h===clearTimeout)return clearTimeout(t);if((h===r||!h)&&clearTimeout)return h=clearTimeout,clearTimeout(t);try{return h(t)}catch(e){try{return h.call(null,t)}catch(e){return h.call(this,t)}}}function s(){y&&l&&(y=!1,l.length?d=l.concat(d):g=-1,d.length&&a())}function a(){if(!y){var t=o(s);y=!0;for(var e=d.length;e;){for(l=d,d=[];++g1)for(var n=1;n100)){var e=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(t);if(e){var n=parseFloat(e[1]),r=(e[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"yrs":case"yr":case"y":return n*u;case"days":case"day":case"d":return n*p;case"hours":case"hour":case"hrs":case"hr":case"h":return n*c;case"minutes":case"minute":case"mins":case"min":case"m":return n*a;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n;default:return}}}}function r(t){return t>=p?Math.round(t/p)+"d":t>=c?Math.round(t/c)+"h":t>=a?Math.round(t/a)+"m":t>=s?Math.round(t/s)+"s":t+"ms"}function o(t){return i(t,p,"day")||i(t,c,"hour")||i(t,a,"minute")||i(t,s,"second")||t+" ms"}function i(t,e,n){if(!(t0)return n(t);if("number"===i&&isNaN(t)===!1)return e["long"]?o(t):r(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},function(t,e,n){function r(){}function o(t){var n=""+t.type;if(e.BINARY_EVENT!==t.type&&e.BINARY_ACK!==t.type||(n+=t.attachments+"-"),t.nsp&&"/"!==t.nsp&&(n+=t.nsp+","),null!=t.id&&(n+=t.id),null!=t.data){var r=i(t.data);if(r===!1)return m;n+=r}return f("encoded %j as %s",t,n),n}function i(t){try{return JSON.stringify(t)}catch(e){return!1}}function s(t,e){function n(t){var n=d.deconstructPacket(t),r=o(n.packet),i=n.buffers;i.unshift(r),e(i)}d.removeBlobs(t,n)}function a(){this.reconstructor=null}function c(t){var n=0,r={type:Number(t.charAt(0))};if(null==e.types[r.type])return h("unknown packet type "+r.type);if(e.BINARY_EVENT===r.type||e.BINARY_ACK===r.type){for(var o="";"-"!==t.charAt(++n)&&(o+=t.charAt(n),n!=t.length););if(o!=Number(o)||"-"!==t.charAt(n))throw new Error("Illegal attachments");r.attachments=Number(o)}if("/"===t.charAt(n+1))for(r.nsp="";++n;){var i=t.charAt(n);if(","===i)break;if(r.nsp+=i,n===t.length)break}else r.nsp="/";var s=t.charAt(n+1);if(""!==s&&Number(s)==s){for(r.id="";++n;){var i=t.charAt(n);if(null==i||Number(i)!=i){--n;break}if(r.id+=t.charAt(n),n===t.length)break}r.id=Number(r.id)}if(t.charAt(++n)){var a=p(t.substr(n)),c=a!==!1&&(r.type===e.ERROR||y(a));if(!c)return h("invalid payload");r.data=a}return f("decoded %s as %j",t,r),r}function p(t){try{return JSON.parse(t)}catch(e){return!1}}function u(t){this.reconPack=t,this.buffers=[]}function h(t){return{type:e.ERROR,data:"parser error: "+t}}var f=n(3)("socket.io-parser"),l=n(8),d=n(9),y=n(10),g=n(11);e.protocol=4,e.types=["CONNECT","DISCONNECT","EVENT","ACK","ERROR","BINARY_EVENT","BINARY_ACK"],e.CONNECT=0,e.DISCONNECT=1,e.EVENT=2,e.ACK=3,e.ERROR=4,e.BINARY_EVENT=5,e.BINARY_ACK=6,e.Encoder=r,e.Decoder=a;var m=e.ERROR+'"encode error"';r.prototype.encode=function(t,n){if(f("encoding packet %j",t),e.BINARY_EVENT===t.type||e.BINARY_ACK===t.type)s(t,n);else{var r=o(t);n([r])}},l(a.prototype),a.prototype.add=function(t){var n;if("string"==typeof t)n=c(t),e.BINARY_EVENT===n.type||e.BINARY_ACK===n.type?(this.reconstructor=new u(n),0===this.reconstructor.reconPack.attachments&&this.emit("decoded",n)):this.emit("decoded",n);else{if(!g(t)&&!t.base64)throw new Error("Unknown type: "+t);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");n=this.reconstructor.takeBinaryData(t),n&&(this.reconstructor=null,this.emit("decoded",n))}},a.prototype.destroy=function(){this.reconstructor&&this.reconstructor.finishedReconstruction()},u.prototype.takeBinaryData=function(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){var e=d.reconstructPacket(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null},u.prototype.finishedReconstruction=function(){this.reconPack=null,this.buffers=[]}},function(t,e,n){function r(t){if(t)return o(t)}function o(t){for(var e in r.prototype)t[e]=r.prototype[e];return t}t.exports=r,r.prototype.on=r.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},r.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n=this._callbacks["$"+t];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var r,o=0;o0&&!this.encoding){var t=this.packetBuffer.shift();this.packet(t)}},r.prototype.cleanup=function(){u("cleanup");for(var t=this.subs.length,e=0;e=this._reconnectionAttempts)u("reconnect failed"),this.backoff.reset(),this.emitAll("reconnect_failed"),this.reconnecting=!1;else{var e=this.backoff.duration();u("will wait %dms before reconnect attempt",e),this.reconnecting=!0;var n=setTimeout(function(){t.skipReconnect||(u("attempting reconnect"),t.emitAll("reconnect_attempt",t.backoff.attempts),t.emitAll("reconnecting",t.backoff.attempts),t.skipReconnect||t.open(function(e){e?(u("reconnect attempt error"),t.reconnecting=!1,t.reconnect(),t.emitAll("reconnect_error",e.data)):(u("reconnect success"),t.onreconnect())}))},e);this.subs.push({destroy:function(){clearTimeout(n)}})}},r.prototype.onreconnect=function(){var t=this.backoff.attempts;this.reconnecting=!1,this.backoff.reset(),this.updateSocketIds(),this.emitAll("reconnect",t)}},function(t,e,n){t.exports=n(14),t.exports.parser=n(22)},function(t,e,n){function r(t,e){return this instanceof r?(e=e||{},t&&"object"==typeof t&&(e=t,t=null),t?(t=u(t),e.hostname=t.host,e.secure="https"===t.protocol||"wss"===t.protocol,e.port=t.port,t.query&&(e.query=t.query)):e.host&&(e.hostname=u(e.host).host),this.secure=null!=e.secure?e.secure:"undefined"!=typeof location&&"https:"===location.protocol,e.hostname&&!e.port&&(e.port=this.secure?"443":"80"),this.agent=e.agent||!1,this.hostname=e.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=e.port||("undefined"!=typeof location&&location.port?location.port:this.secure?443:80),this.query=e.query||{},"string"==typeof this.query&&(this.query=h.decode(this.query)),this.upgrade=!1!==e.upgrade,this.path=(e.path||"/engine.io").replace(/\/$/,"")+"/",this.forceJSONP=!!e.forceJSONP,this.jsonp=!1!==e.jsonp,this.forceBase64=!!e.forceBase64,this.enablesXDR=!!e.enablesXDR,this.withCredentials=!1!==e.withCredentials,this.timestampParam=e.timestampParam||"t",this.timestampRequests=e.timestampRequests,this.transports=e.transports||["polling","websocket"],this.transportOptions=e.transportOptions||{},this.readyState="",this.writeBuffer=[],this.prevBufferLen=0,this.policyPort=e.policyPort||843,this.rememberUpgrade=e.rememberUpgrade||!1,this.binaryType=null,this.onlyBinaryUpgrades=e.onlyBinaryUpgrades,this.perMessageDeflate=!1!==e.perMessageDeflate&&(e.perMessageDeflate||{}),!0===this.perMessageDeflate&&(this.perMessageDeflate={}),this.perMessageDeflate&&null==this.perMessageDeflate.threshold&&(this.perMessageDeflate.threshold=1024),this.pfx=e.pfx||null,this.key=e.key||null,this.passphrase=e.passphrase||null,this.cert=e.cert||null,this.ca=e.ca||null,this.ciphers=e.ciphers||null,this.rejectUnauthorized=void 0===e.rejectUnauthorized||e.rejectUnauthorized,this.forceNode=!!e.forceNode,this.isReactNative="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase(),("undefined"==typeof self||this.isReactNative)&&(e.extraHeaders&&Object.keys(e.extraHeaders).length>0&&(this.extraHeaders=e.extraHeaders),e.localAddress&&(this.localAddress=e.localAddress)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingIntervalTimer=null,this.pingTimeoutTimer=null,void this.open()):new r(t,e)}function o(t){var e={};for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}var i=n(15),s=n(8),a=n(3)("engine.io-client:socket"),c=n(36),p=n(22),u=n(2),h=n(30);t.exports=r,r.priorWebsocketSuccess=!1,s(r.prototype),r.protocol=p.protocol,r.Socket=r,r.Transport=n(21),r.transports=n(15),r.parser=n(22),r.prototype.createTransport=function(t){a('creating transport "%s"',t);var e=o(this.query);e.EIO=p.protocol,e.transport=t;var n=this.transportOptions[t]||{};this.id&&(e.sid=this.id);var r=new i[t]({query:e,socket:this,agent:n.agent||this.agent,hostname:n.hostname||this.hostname,port:n.port||this.port,secure:n.secure||this.secure,path:n.path||this.path,forceJSONP:n.forceJSONP||this.forceJSONP,jsonp:n.jsonp||this.jsonp,forceBase64:n.forceBase64||this.forceBase64,enablesXDR:n.enablesXDR||this.enablesXDR,withCredentials:n.withCredentials||this.withCredentials,timestampRequests:n.timestampRequests||this.timestampRequests,timestampParam:n.timestampParam||this.timestampParam,policyPort:n.policyPort||this.policyPort,pfx:n.pfx||this.pfx,key:n.key||this.key,passphrase:n.passphrase||this.passphrase,cert:n.cert||this.cert,ca:n.ca||this.ca,ciphers:n.ciphers||this.ciphers,rejectUnauthorized:n.rejectUnauthorized||this.rejectUnauthorized,perMessageDeflate:n.perMessageDeflate||this.perMessageDeflate,extraHeaders:n.extraHeaders||this.extraHeaders,forceNode:n.forceNode||this.forceNode,localAddress:n.localAddress||this.localAddress,requestTimeout:n.requestTimeout||this.requestTimeout,protocols:n.protocols||void 0,isReactNative:this.isReactNative});return r},r.prototype.open=function(){var t;if(this.rememberUpgrade&&r.priorWebsocketSuccess&&this.transports.indexOf("websocket")!==-1)t="websocket";else{if(0===this.transports.length){var e=this;return void setTimeout(function(){e.emit("error","No transports available")},0)}t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(n){return this.transports.shift(),void this.open()}t.open(),this.setTransport(t)},r.prototype.setTransport=function(t){a("setting transport %s",t.name);var e=this;this.transport&&(a("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=t,t.on("drain",function(){e.onDrain()}).on("packet",function(t){e.onPacket(t)}).on("error",function(t){e.onError(t)}).on("close",function(){e.onClose("transport close")})},r.prototype.probe=function(t){function e(){if(f.onlyBinaryUpgrades){var e=!this.supportsBinary&&f.transport.supportsBinary;h=h||e}h||(a('probe transport "%s" opened',t),u.send([{type:"ping",data:"probe"}]),u.once("packet",function(e){if(!h)if("pong"===e.type&&"probe"===e.data){if(a('probe transport "%s" pong',t),f.upgrading=!0,f.emit("upgrading",u),!u)return;r.priorWebsocketSuccess="websocket"===u.name,a('pausing current transport "%s"',f.transport.name),f.transport.pause(function(){h||"closed"!==f.readyState&&(a("changing transport and sending upgrade packet"),p(),f.setTransport(u),u.send([{type:"upgrade"}]),f.emit("upgrade",u),u=null,f.upgrading=!1,f.flush())})}else{a('probe transport "%s" failed',t);var n=new Error("probe error");n.transport=u.name,f.emit("upgradeError",n)}}))}function n(){h||(h=!0,p(),u.close(),u=null)}function o(e){var r=new Error("probe error: "+e);r.transport=u.name,n(),a('probe transport "%s" failed because of error: %s',t,e),f.emit("upgradeError",r)}function i(){o("transport closed")}function s(){o("socket closed")}function c(t){u&&t.name!==u.name&&(a('"%s" works - aborting "%s"',t.name,u.name),n())}function p(){u.removeListener("open",e),u.removeListener("error",o),u.removeListener("close",i),f.removeListener("close",s),f.removeListener("upgrading",c)}a('probing transport "%s"',t);var u=this.createTransport(t,{probe:1}),h=!1,f=this;r.priorWebsocketSuccess=!1,u.once("open",e),u.once("error",o),u.once("close",i),this.once("close",s),this.once("upgrading",c),u.open()},r.prototype.onOpen=function(){if(a("socket open"),this.readyState="open",r.priorWebsocketSuccess="websocket"===this.transport.name,this.emit("open"),this.flush(),"open"===this.readyState&&this.upgrade&&this.transport.pause){a("starting upgrade probes");for(var t=0,e=this.upgrades.length;t1?{type:b[o],data:t.substring(1)}:{type:b[o]}:w}var i=new Uint8Array(t),o=i[0],s=f(t,1);return k&&"blob"===n&&(s=new k([s])),{type:b[o],data:s}},e.decodeBase64Packet=function(t,e){var n=b[t.charAt(0)];if(!p)return{type:n,data:{base64:!0,data:t.substr(1)}};var r=p.decode(t.substr(1));return"blob"===e&&k&&(r=new k([r])),{type:n,data:r}},e.encodePayload=function(t,n,r){function o(t){return t.length+":"+t}function i(t,r){e.encodePacket(t,!!s&&n,!1,function(t){r(null,o(t))})}"function"==typeof n&&(r=n,n=null);var s=h(t);return n&&s?k&&!m?e.encodePayloadAsBlob(t,r):e.encodePayloadAsArrayBuffer(t,r):t.length?void c(t,i,function(t,e){return r(e.join(""))}):r("0:")},e.decodePayload=function(t,n,r){if("string"!=typeof t)return e.decodePayloadAsBinary(t,n,r);"function"==typeof n&&(r=n,n=null);var o;if(""===t)return r(w,0,1);for(var i,s,a="",c=0,p=t.length;c0;){for(var s=new Uint8Array(o),a=0===s[0],c="",p=1;255!==s[p];p++){if(c.length>310)return r(w,0,1);c+=s[p]}o=f(o,2+c.length),c=parseInt(c);var u=f(o,0,c);if(a)try{u=String.fromCharCode.apply(null,new Uint8Array(u))}catch(h){var l=new Uint8Array(u);u="";for(var p=0;pr&&(n=r),e>=r||e>=n||0===r)return new ArrayBuffer(0);for(var o=new Uint8Array(t),i=new Uint8Array(n-e),s=e,a=0;s=55296&&e<=56319&&o65535&&(e-=65536,o+=d(e>>>10&1023|55296),e=56320|1023&e),o+=d(e);return o}function o(t,e){if(t>=55296&&t<=57343){if(e)throw Error("Lone surrogate U+"+t.toString(16).toUpperCase()+" is not a scalar value");return!1}return!0}function i(t,e){return d(t>>e&63|128)}function s(t,e){if(0==(4294967168&t))return d(t);var n="";return 0==(4294965248&t)?n=d(t>>6&31|192):0==(4294901760&t)?(o(t,e)||(t=65533),n=d(t>>12&15|224),n+=i(t,6)):0==(4292870144&t)&&(n=d(t>>18&7|240),n+=i(t,12),n+=i(t,6)),n+=d(63&t|128)}function a(t,e){e=e||{};for(var r,o=!1!==e.strict,i=n(t),a=i.length,c=-1,p="";++c=f)throw Error("Invalid byte index");var t=255&h[l];if(l++,128==(192&t))return 63&t;throw Error("Invalid continuation byte")}function p(t){var e,n,r,i,s;if(l>f)throw Error("Invalid byte index");if(l==f)return!1;if(e=255&h[l],l++,0==(128&e))return e;if(192==(224&e)){if(n=c(),s=(31&e)<<6|n,s>=128)return s;throw Error("Invalid continuation byte")}if(224==(240&e)){if(n=c(),r=c(),s=(15&e)<<12|n<<6|r,s>=2048)return o(s,t)?s:65533;throw Error("Invalid continuation byte")}if(240==(248&e)&&(n=c(),r=c(),i=c(),s=(7&e)<<18|n<<12|r<<6|i,s>=65536&&s<=1114111))return s;throw Error("Invalid UTF-8 detected")}function u(t,e){e=e||{};var o=!1!==e.strict;h=n(t),f=h.length,l=0;for(var i,s=[];(i=p(o))!==!1;)s.push(i);return r(s)}/*! https://mths.be/utf8js v2.1.2 by @mathias */ +var h,f,l,d=String.fromCharCode;t.exports={version:"2.1.2",encode:a,decode:u}},function(t,e){!function(t){"use strict";e.encode=function(e){var n,r=new Uint8Array(e),o=r.length,i="";for(n=0;n>2],i+=t[(3&r[n])<<4|r[n+1]>>4],i+=t[(15&r[n+1])<<2|r[n+2]>>6],i+=t[63&r[n+2]];return o%3===2?i=i.substring(0,i.length-1)+"=":o%3===1&&(i=i.substring(0,i.length-2)+"=="),i},e.decode=function(e){var n,r,o,i,s,a=.75*e.length,c=e.length,p=0;"="===e[e.length-1]&&(a--,"="===e[e.length-2]&&a--);var u=new ArrayBuffer(a),h=new Uint8Array(u);for(n=0;n>4,h[p++]=(15&o)<<4|i>>2,h[p++]=(3&i)<<6|63&s;return u}}("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")},function(t,e){function n(t){return t.map(function(t){if(t.buffer instanceof ArrayBuffer){var e=t.buffer;if(t.byteLength!==e.byteLength){var n=new Uint8Array(t.byteLength);n.set(new Uint8Array(e,t.byteOffset,t.byteLength)),e=n.buffer}return e}return t})}function r(t,e){e=e||{};var r=new i;return n(t).forEach(function(t){r.append(t)}),e.type?r.getBlob(e.type):r.getBlob()}function o(t,e){return new Blob(n(t),e||{})}var i="undefined"!=typeof i?i:"undefined"!=typeof WebKitBlobBuilder?WebKitBlobBuilder:"undefined"!=typeof MSBlobBuilder?MSBlobBuilder:"undefined"!=typeof MozBlobBuilder&&MozBlobBuilder,s=function(){try{var t=new Blob(["hi"]);return 2===t.size}catch(e){return!1}}(),a=s&&function(){try{var t=new Blob([new Uint8Array([1,2])]);return 2===t.size}catch(e){return!1}}(),c=i&&i.prototype.append&&i.prototype.getBlob;"undefined"!=typeof Blob&&(r.prototype=Blob.prototype,o.prototype=Blob.prototype),t.exports=function(){return s?a?Blob:o:c?r:void 0}()},function(t,e){e.encode=function(t){var e="";for(var n in t)t.hasOwnProperty(n)&&(e.length&&(e+="&"),e+=encodeURIComponent(n)+"="+encodeURIComponent(t[n]));return e},e.decode=function(t){for(var e={},n=t.split("&"),r=0,o=n.length;r0);return e}function r(t){var e=0;for(u=0;u';i=document.createElement(e)}catch(t){i=document.createElement("iframe"),i.name=o.iframeId,i.src="javascript:0"}i.id=o.iframeId,o.form.appendChild(i),o.iframe=i}var o=this;if(!this.form){var i,s=document.createElement("form"),a=document.createElement("textarea"),c=this.iframeId="eio_iframe_"+this.index;s.className="socketio",s.style.position="absolute",s.style.top="-1000px",s.style.left="-1000px",s.target=c,s.method="POST",s.setAttribute("accept-charset","utf-8"),a.name="d",s.appendChild(a),document.body.appendChild(s),this.form=s,this.area=a}this.form.action=this.uri(),r(),t=t.replace(u,"\\\n"),this.area.value=t.replace(p,"\\n");try{this.form.submit()}catch(h){}this.iframe.attachEvent?this.iframe.onreadystatechange=function(){"complete"===o.iframe.readyState&&n()}:this.iframe.onload=n}},function(t,e,n){function r(t){var e=t&&t.forceBase64;e&&(this.supportsBinary=!1),this.perMessageDeflate=t.perMessageDeflate,this.usingBrowserWebSocket=o&&!t.forceNode,this.protocols=t.protocols,this.usingBrowserWebSocket||(l=i),s.call(this,t)}var o,i,s=n(21),a=n(22),c=n(30),p=n(31),u=n(32),h=n(3)("engine.io-client:websocket");if("undefined"!=typeof WebSocket?o=WebSocket:"undefined"!=typeof self&&(o=self.WebSocket||self.MozWebSocket),"undefined"==typeof window)try{i=n(35)}catch(f){}var l=o||i;t.exports=r,p(r,s),r.prototype.name="websocket",r.prototype.supportsBinary=!0,r.prototype.doOpen=function(){if(this.check()){var t=this.uri(),e=this.protocols,n={};this.isReactNative||(n.agent=this.agent,n.perMessageDeflate=this.perMessageDeflate,n.pfx=this.pfx,n.key=this.key,n.passphrase=this.passphrase,n.cert=this.cert,n.ca=this.ca,n.ciphers=this.ciphers,n.rejectUnauthorized=this.rejectUnauthorized),this.extraHeaders&&(n.headers=this.extraHeaders),this.localAddress&&(n.localAddress=this.localAddress);try{this.ws=this.usingBrowserWebSocket&&!this.isReactNative?e?new l(t,e):new l(t):new l(t,e,n)}catch(r){return this.emit("error",r)}void 0===this.ws.binaryType&&(this.supportsBinary=!1),this.ws.supports&&this.ws.supports.binary?(this.supportsBinary=!0,this.ws.binaryType="nodebuffer"):this.ws.binaryType="arraybuffer",this.addEventListeners()}},r.prototype.addEventListeners=function(){var t=this;this.ws.onopen=function(){t.onOpen()},this.ws.onclose=function(){t.onClose()},this.ws.onmessage=function(e){t.onData(e.data)},this.ws.onerror=function(e){t.onError("websocket error",e)}},r.prototype.write=function(t){function e(){n.emit("flush"),setTimeout(function(){n.writable=!0,n.emit("drain")},0)}var n=this;this.writable=!1;for(var r=t.length,o=0,i=r;o0&&t.jitter<=1?t.jitter:0,this.attempts=0}t.exports=n,n.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(t){this.ms=t},n.prototype.setMax=function(t){this.max=t},n.prototype.setJitter=function(t){this.jitter=t}}])}); +//# sourceMappingURL=socket.io.js.map diff --git a/lib/socket.js b/lib/socket.js index 1fe10ec..214a0d3 100644 --- a/lib/socket.js +++ b/lib/socket.js @@ -15,16 +15,13 @@ const ERROR_PERMISSION = 'permissionError'; const COMMAND_RE_AUTHENTICATE = 'reauthenticate'; // From settings used only secure, auth and crossDomain -function IOSocket(server, settings, adapter, ignore, store) { +function IOSocket(server, settings, adapter) { if (!(this instanceof IOSocket)) { - return new IOSocket(server, settings, adapter, ignore, store); + return new IOSocket(server, settings, adapter); } - socketio = require('./ws'); + socketio = require('socket.io'); - store = store || settings.store; - - const userKey = 'connect.sid'; // const this.settings = settings || {}; this.adapter = adapter; this.webServer = server; @@ -32,13 +29,9 @@ function IOSocket(server, settings, adapter, ignore, store) { this.thersholdInterval = null; let cookieParser; - let passport; - let passportSocketIo; if (settings.auth) { - cookieParser = require('cookie-parser'); - passport = require('passport'); - passportSocketIo = require('./passportSocket'); + cookieParser = require('cookie-parser'); } const that = this; @@ -56,27 +49,67 @@ function IOSocket(server, settings, adapter, ignore, store) { // Extract username from socket function getUserFromSocket(socket, callback) { let wait = false; - if (typeof callback !== 'function') { - return; - } - try { - if (socket.conn.request.sessionID) { - socket._sessionID = socket.conn.request.sessionID; - wait = true; - if (store) { - store.get(socket.conn.request.sessionID, (err, obj) => { - if (obj && obj.passport && obj.passport.user) { - callback(null, obj.passport.user ? 'system.user.' + obj.passport.user : ''); + if (socket.handshake.headers.cookie && (!socket.request || !socket.request._query || !socket.request._query.user)) { + let cookie = decodeURIComponent(socket.handshake.headers.cookie); + let m = cookie.match(/connect\.sid=(.+)/); + if (m) { + // If session cookie exists + let c = m[1].split(';')[0]; + let sessionID = cookieParser.signedCookie(c, that.settings.secret); + if (sessionID) { + // Get user for session + wait = true; + that.settings.store.get(sessionID, (err, obj) => { + if (obj && obj.passport && obj.passport.user) { + socket._sessionID = sessionID; + if (typeof callback === 'function') { + callback(null, obj.passport.user); + } else { + that.adapter.log.warn('[getUserFromSocket] Invalid callback'); + } + } else { + if (typeof callback === 'function') { + callback('unknown user'); + } else { + that.adapter.log.warn('[getUserFromSocket] Invalid callback') + } + } + }); + } + } + } + + if (!wait) { + let user = socket.request._query.user; + let pass = socket.request._query.pass; + if (user && pass) { + wait = true; + that.adapter.checkPassword(user, pass, (res) => { + if (res) { + that.adapter.log.debug('Logged in: ' + user); + if (typeof callback === 'function') { + callback(null, user); + } else { + that.adapter.log.warn('[getUserFromSocket] Invalid callback') + } + } else { + that.adapter.log.warn(`Invalid password or user name: ${user}, ${pass[0]}***(${pass.length})`); + if (typeof callback === 'function') { + callback('unknown user'); + } else { + that.adapter.log.warn('[getUserFromSocket] Invalid callback') + } } }); } } } catch (e) { - // ignore + that.adapter.log.error(e); + wait = false; } - !wait && callback('Cannot detect user'); + !wait && typeof callback === 'function' && callback('Cannot detect user'); } function disableEventThreshold(readAll) { @@ -89,14 +122,14 @@ function IOSocket(server, settings, adapter, ignore, store) { setTimeout(() => { if (readAll) { - that.adapter.getForeignStates('*', ()/*(err, res)*/ => { + that.adapter.getForeignStates('*', (err, res) => { that.adapter.log.info('received all states'); - /*for (let id in res) { + for (const id in res) { if (Object.prototype.hasOwnProperty.call(res, id) && JSON.stringify(states[id]) !== JSON.stringify(res[id])) { that.server && that.server.sockets && that.server.sockets.emit('stateChange', id, res[id]); states[id] = res[id]; } - }*/ + } }); } @@ -124,57 +157,31 @@ function IOSocket(server, settings, adapter, ignore, store) { function getClientAddress(socket) { let address; - if (socket.connection) { - address = socket.connection && socket.connection.remoteAddress; - } else { - address = socket.ws._socket.remoteAddress; - } - - if (!address && socket.handshake) { + if (socket.handshake) { address = socket.handshake.address; } - if (!address && socket.conn.request && socket.conn.request.connection) { - address = socket.conn.request.connection.remoteAddress; + if (!address && socket.request && socket.request.connection) { + address = socket.request.connection.remoteAddress; } return address; } - function onAuthorizeSuccess(data, accept) { - adapter.log.debug('successful connection to socket.io from ' + data.connection.remoteAddress); - //adapter.log.info(JSON.stringify(data)); - - accept(); - } - - function onAuthorizeFail(data, message, error, accept) { - setTimeout(() => data.socket.emit(COMMAND_RE_AUTHENTICATE), 100); - - error && adapter.log.error(`failed connection to socket.io from ${data.connection.remoteAddress}:`, message); - - if (error) { - accept(new Error(message)); - } else { - accept(new Error('failed connection to socket.io: ' + message));//null, false); - } - // this error will be sent to the user as a special error-package - // see: http://socket.io/docs/client-api/#socket > error-object - } - - this.initSocket = function (socket, cb) { + this.initSocket = function (socket) { if (!socket._acl) { if (that.settings.auth) { getUserFromSocket(socket, (err, user) => { if (err || !user) { socket.emit(COMMAND_RE_AUTHENTICATE); - that.adapter.log.error(`socket.io ${err || 'No user found in cookies'}`); + that.adapter.log.error(`socket.io [init] ${err || 'No user found in cookies'}`); + socket.disconnect(); } else { socket._secure = true; that.adapter.log.debug(`socket.io client ${user} connected`); - that.adapter.calculatePermissions(user, commandsPermissions, acl => { + that.adapter.calculatePermissions(`system.user.${user}`, commandsPermissions, acl => { const address = getClientAddress(socket); // socket._acl = acl; socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings); - socketEvents(socket, address, cb); + socketEvents(socket, address); }); } }); @@ -183,12 +190,12 @@ function IOSocket(server, settings, adapter, ignore, store) { const address = getClientAddress(socket); // socket._acl = acl; socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings); - socketEvents(socket, address, cb); + socketEvents(socket, address); }); } } else { const address = getClientAddress(socket); - socketEvents(socket, address, cb); + socketEvents(socket, address); } }; @@ -220,7 +227,7 @@ function IOSocket(server, settings, adapter, ignore, store) { return null; } - wildCardIps.forEach(function (ip) { + wildCardIps.forEach(ip => { const ipParts = ip.split('.'); if (ipParts.length === 4) { for (let i = 0; i < 4; i++) { @@ -294,9 +301,8 @@ function IOSocket(server, settings, adapter, ignore, store) { if (socket) { socket._subscribe = socket._subscribe || {}; } - if (!this.subscribes[type]) { - this.subscribes[type] = {}; - } + + this.subscribes[type] = this.subscribes[type] || {}; let s; if (socket) { @@ -310,7 +316,7 @@ function IOSocket(server, settings, adapter, ignore, store) { const p = pattern2RegEx(pattern); if (p === null) { - return this.adapter.log.warn('Empty pattern!'); + return this.adapter.log.warn('Empty pattern on subscribe!'); } if (socket) { s.push({pattern: pattern, regex: new RegExp(p)}); @@ -325,9 +331,7 @@ function IOSocket(server, settings, adapter, ignore, store) { this.adapter.subscribeForeignObjects(pattern); } } else if (type === 'log') { - if (this.adapter.requireLog) { - this.adapter.requireLog(true); - } + this.adapter.requireLog && this.adapter.requireLog(true); } } else { this.subscribes[type][pattern]++; @@ -349,9 +353,7 @@ function IOSocket(server, settings, adapter, ignore, store) { this.unsubscribe = function (socket, type, pattern) { //console.log((socket._name || socket.id) + ' unsubscribe ' + pattern); - if (!this.subscribes[type]) { - this.subscribes[type] = {}; - } + this.subscribes[type] = this.subscribes[type] || {}; if (socket) { if (!socket._subscribe || !socket._subscribe[type]) { @@ -359,7 +361,6 @@ function IOSocket(server, settings, adapter, ignore, store) { } for (let i = socket._subscribe[type].length - 1; i >= 0; i--) { if (socket._subscribe[type][i].pattern === pattern) { - // Remove pattern from global list if (this.subscribes[type][pattern] !== undefined) { this.subscribes[type][pattern]--; @@ -369,14 +370,10 @@ function IOSocket(server, settings, adapter, ignore, store) { this.adapter.unsubscribeForeignStates(pattern); } else if (type === 'objectChange') { //console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern); - if (this.adapter.unsubscribeForeignObjects) { - this.adapter.unsubscribeForeignObjects(pattern); - } + this.adapter.unsubscribeForeignObjects && this.adapter.unsubscribeForeignObjects(pattern); } else if (type === 'log') { //console.log((socket._name || socket.id) + ' requireLog false'); - if (this.adapter.requireLog) { - this.adapter.requireLog(false); - } + this.adapter.requireLog && this.adapter.requireLog(false); } delete this.subscribes[type][pattern]; } @@ -397,14 +394,10 @@ function IOSocket(server, settings, adapter, ignore, store) { this.adapter.unsubscribeForeignStates(pattern); } else if (type === 'objectChange') { //console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern); - if (this.adapter.unsubscribeForeignObjects) { - this.adapter.unsubscribeForeignObjects(pattern); - } + this.adapter.unsubscribeForeignObjects && this.adapter.unsubscribeForeignObjects(pattern); } else if (type === 'log') { //console.log((socket._name || socket.id) + ' requireLog false'); - if (this.adapter.requireLog) { - this.adapter.requireLog(false); - } + this.adapter.requireLog && this.adapter.requireLog(false); } delete this.subscribes[type][pattern]; } @@ -419,14 +412,10 @@ function IOSocket(server, settings, adapter, ignore, store) { this.adapter.unsubscribeForeignStates(pattern); } else if (type === 'objectChange') { //console.log((socket._name || socket.id) + ' unsubscribeForeignObjects ' + pattern); - if (this.adapter.unsubscribeForeignObjects) { - this.adapter.unsubscribeForeignObjects(pattern); - } + this.adapter.unsubscribeForeignObjects && this.adapter.unsubscribeForeignObjects(pattern); } else if (type === 'log') { //console.log((socket._name || socket.id) + ' requireLog false'); - if (this.adapter.requireLog) { - this.adapter.requireLog(false); - } + this.adapter.requireLog && this.adapter.requireLog(false); } delete this.subscribes[type][pattern]; } @@ -458,13 +447,9 @@ function IOSocket(server, settings, adapter, ignore, store) { if (type === 'stateChange') { that.adapter.unsubscribeForeignStates(pattern); } else if (type === 'objectChange') { - if (that.adapter.unsubscribeForeignObjects) { - that.adapter.unsubscribeForeignObjects(pattern); - } + that.adapter.unsubscribeForeignObjects && that.adapter.unsubscribeForeignObjects(pattern); } else if (type === 'log') { - if (that.adapter.requireLog) { - that.adapter.requireLog(false); - } + that.adapter.requireLog && that.adapter.requireLog(false); } delete that.subscribes[type][pattern]; } @@ -485,13 +470,9 @@ function IOSocket(server, settings, adapter, ignore, store) { if (type === 'stateChange') { that.adapter.subscribeForeignStates(pattern); } else if (type === 'objectChange') { - if (that.adapter.subscribeForeignObjects) { - that.adapter.subscribeForeignObjects(pattern); - } + that.adapter.subscribeForeignObjects && that.adapter.subscribeForeignObjects(pattern); } else if (type === 'log') { - if (that.adapter.requireLog) { - that.adapter.requireLog(true); - } + that.adapter.requireLog && that.adapter.requireLog(true); } } else { that.subscribes[type][pattern]++; @@ -506,58 +487,36 @@ function IOSocket(server, settings, adapter, ignore, store) { const s = socket._subscribe[type]; for (let i = 0; i < s.length; i++) { if (s[i].regex.test(id)) { - return socket.emit(type, id, obj); + updateSession(socket); + socket.emit(type, id, obj); + return; } } } - function waitForSessionEnd(socket) { - if (socket._sessionTimer) { - clearTimeout(socket._sessionTimer); - socket._sessionTimer = null; - } - const sessionId = socket._sessionID; - store && store.get(sessionId, (err, obj) => { - if (obj) { - const expires = new Date(obj.cookie.expires); - const interval = expires.getTime() - Date.now(); - if (interval > 0) { - socket._sessionTimer = socket._sessionTimer || setTimeout(() => waitForSessionEnd(socket), interval > 3600000 ? 3600000 : interval); - socket.emit('expire', expires.getTime()); - } else { - adapter.log.warn('REAUTHENTICATE!'); - socket.emit(COMMAND_RE_AUTHENTICATE); - } - } else { - adapter.log.warn('REAUTHENTICATE!'); - socket && socket.emit && socket.emit(COMMAND_RE_AUTHENTICATE); - } - }); - } - // update session ID, but not ofter than 60 seconds function updateSession(socket) { - const sessionId = socket._sessionID; - const now = Date.now(); - if (sessionId && (!socket._lastUpdate || now - socket._lastUpdate > 10000)) { - socket._lastUpdate = now; - store && store.get(sessionId, (err, obj) => { - // obj = {"cookie":{"originalMaxAge":2592000000,"expires":"2020-09-24T18:09:50.377Z","httpOnly":true,"path":"/"},"passport":{"user":"admin"}} - if (obj) { - // start timer - !socket._sessionTimer && waitForSessionEnd(socket); - /*obj.ttl = obj.ttl || (new Date(obj.cookie.expires).getTime() - now); - const expires = new Date(); - expires.setMilliseconds(expires.getMilliseconds() + obj.ttl + 10000); - obj.cookie.expires = expires.toISOString(); - console.log('Session ' + sessionId + ' expires on ' + obj.cookie.expires); - - store.set(sessionId, obj);*/ - } else { - adapter.log.warn('REAUTHENTICATE!'); - socket.emit(COMMAND_RE_AUTHENTICATE); - } - }); + if (socket._sessionID) { + let time = Date.now(); + if (socket._lastActivity && time - socket._lastActivity > settings.ttl * 1000) { + socket.emit(COMMAND_RE_AUTHENTICATE); + socket.disconnect(); + return false; + } + socket._lastActivity = time; + if (!socket._sessionTimer) { + socket._sessionTimer = setTimeout(() => { + socket._sessionTimer = null; + that.settings.store.get(socket._sessionID, (err, obj) => { + if (obj) { + that.adapter.setSession(socket._sessionID, settings.ttl, obj); + } else { + socket.emit(COMMAND_RE_AUTHENTICATE); + socket.disconnect(); + } + }); + }, 60000); + } } return true; } @@ -754,10 +713,10 @@ function IOSocket(server, settings, adapter, ignore, store) { } else { if (commandsPermissions[command]) { socket.emit(ERROR_PERMISSION, { - command: command, + command, type: commandsPermissions[command].type, operation: commandsPermissions[command].operation, - arg: arg + arg }); } else { socket.emit(ERROR_PERMISSION, {command, arg}); @@ -807,13 +766,13 @@ function IOSocket(server, settings, adapter, ignore, store) { function stopAdapter(reason, callback) { reason && that.adapter.log.warn('Adapter stopped. Reason: ' + reason); - that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, function (err, obj) { - err && that.adapter.log.error('[getForeignObject]: ' + err); + that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, (err, obj) => { + err && that.adapter.log.error('[stopAdapter/getForeignObject]: ' + err); if (obj) { obj.common.enabled = false; setTimeout(() => { that.adapter.setForeignObject(obj._id, obj, err => { - err && that.adapter.log.error('[setForeignObject]: ' + err); + err && that.adapter.log.error('[stopAdapter/setForeignObject]: ' + err); callback && callback(); }); }, 5000); @@ -827,16 +786,14 @@ function IOSocket(server, settings, adapter, ignore, store) { if (!url) { that.adapter.log.warn('Received redirect command, but no URL'); } else { - that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, function (err, obj) { + that.adapter.getForeignObject('system.adapter.' + that.adapter.namespace, (err, obj) => { err && that.adapter.log.error('redirectAdapter [getForeignObject]: ' + err); if (obj) { obj.native.cloudUrl = url; - setTimeout(() => { - that.adapter.setForeignObject(obj._id, obj, err => { - err && that.adapter.log.error('redirectAdapter [setForeignObject]: ' + err); - callback && callback(); - }); - }, 3000); + setTimeout(() => that.adapter.setForeignObject(obj._id, obj, err => { + err && that.adapter.log.error('redirectAdapter [setForeignObject]: ' + err); + callback && callback(); + }), 3000); } else { callback && callback(); } @@ -848,7 +805,7 @@ function IOSocket(server, settings, adapter, ignore, store) { that.emit && that.emit('connectWait', delaySeconds); } - function socketEvents(socket, address, cb) { + function socketEvents(socket, address) { if (socket.conn) { that.adapter.log.info(`==> Connected ${socket._acl.user} from ${address}`); } else { @@ -1478,11 +1435,6 @@ function IOSocket(server, settings, adapter, ignore, store) { unsubscribeSocket(this, 'log'); that.infoTimeout = that.infoTimeout || setTimeout(updateConnectedInfo, 1000); - if (socket._sessionTimer) { - clearTimeout(socket._sessionTimer); - socket._sessionTimer = null; - } - // if client mode if (!socket.conn) { socket._apiKeyOk = false; @@ -1598,12 +1550,13 @@ function IOSocket(server, settings, adapter, ignore, store) { }); if (socket._sessionID) { - that.adapter.getSession(socket._sessionID, function (obj) { + that.adapter.getSession(socket._sessionID, obj => { if (obj && obj.passport) { socket._acl.user = obj.passport.user; } else { socket._acl.user = ''; socket.emit(COMMAND_RE_AUTHENTICATE); + socket.disconnect(); } if (socket._authPending) { socket._authPending(!!socket._acl.user, true); @@ -1634,13 +1587,15 @@ function IOSocket(server, settings, adapter, ignore, store) { });*/ } else { // if server mode - if (socket._sessionID && adapter.config.auth) { + if (socket.conn.request.sessionID) { socket._secure = true; + socket._sessionID = socket.conn.request.sessionID; // Get user for session - store && store.get(socket._sessionID, (err, obj) => { + that.settings.store.get(socket.conn.request.sessionID, (err, obj) => { if (!obj || !obj.passport) { socket._acl.user = ''; socket.emit(COMMAND_RE_AUTHENTICATE); + socket.disconnect(); } if (socket._authPending) { socket._authPending(!!socket._acl.user, true); @@ -1653,8 +1608,6 @@ function IOSocket(server, settings, adapter, ignore, store) { subscribeSocket(socket, 'objectChange'); subscribeSocket(socket, 'log'); } - - cb && cb(); } function updateConnectedInfo() { @@ -1717,7 +1670,7 @@ function IOSocket(server, settings, adapter, ignore, store) { (function __constructor() { if (that.settings.allowAdmin) { // detect event bursts - that.thersholdInterval = setInterval(function () { + that.thersholdInterval = setInterval(() => { if (!eventsThreshold.active) { if (eventsThreshold.count > eventsThreshold.value) { eventsThreshold.accidents++; @@ -1780,6 +1733,9 @@ function IOSocket(server, settings, adapter, ignore, store) { path.resolve = pathResolve; // restore path.resolve once done that.webServer.__inited = true; } + + // force using only websockets + that.settings.forceWebSockets && that.server.set('transports', ['websocket']); } else { that.server = server; } @@ -1791,15 +1747,36 @@ function IOSocket(server, settings, adapter, ignore, store) { } if (that.settings.auth && that.server) { - that.server.use(passportSocketIo.authorize({ - passport, - cookieParser, - key: userKey, // the name of the cookie where express/connect stores its session_id - secret: settings.secret, // the session_secret to parse the cookie - store, // we NEED to use a sessionstore. no memorystore please - success: onAuthorizeSuccess, // *optional* callback on success - read more below - fail: onAuthorizeFail // *optional* callback on fail/error - read more below - })); + that.server.use((socket, next) => { + if (!socket.request._query.user || !socket.request._query.pass) { + getUserFromSocket(socket, (err, user) => { + if (err || !user) { + socket.emit(COMMAND_RE_AUTHENTICATE); + that.adapter.log.error(`socket.io [use] ${err || 'User not found'}`); + socket.disconnect(); + } else { + socket._secure = true; + that.adapter.calculatePermissions(`system.user.${user}`, commandsPermissions, acl => { + let address = getClientAddress(socket); + // socket._acl = acl; + socket._acl = mergeACLs(address, acl, that.settings.whiteListSettings); + next(); + }); + } + }); + } else { + that.adapter.checkPassword(socket.request._query.user, socket.request._query.pass, res => { + if (res) { + that.adapter.log.debug(`Logged in: ${socket.request._query.user}, ${socket.request._query.pass}`); + next(); + } else { + that.adapter.log.warn(`Invalid password or user name: ${socket.request._query.user}, ${socket.request._query.pass}`); + socket.emit(COMMAND_RE_AUTHENTICATE); + next(new Error('Invalid password or user name')); + } + }); + } + }); } // Enable cross domain access @@ -1810,15 +1787,13 @@ function IOSocket(server, settings, adapter, ignore, store) { that.settings.ttl = that.settings.ttl || 3600; that.server.on('connection', that.initSocket); - that.server.on('error', e => that.adapter.log.error('Server error: ' + e)); + that.server.on('error', (e, details) => that.adapter.log.error(`Server error: ${e}${details ? ' - ' + details : ''}`)); if (settings.port) { that.adapter.log.info(`${settings.secure ? 'Secure ' : ''}socket.io server listening on port ${settings.port}`); } - if (!that.infoTimeout) { - that.infoTimeout = setTimeout(updateConnectedInfo, 1000); - } + that.infoTimeout = that.infoTimeout || setTimeout(updateConnectedInfo, 1000); // if client mode => add event handlers if (that.settings.apikey) { diff --git a/lib/ws.js b/lib/ws.js deleted file mode 100644 index 4338797..0000000 --- a/lib/ws.js +++ /dev/null @@ -1,343 +0,0 @@ -/* jshint -W097 */ -/* jshint strict: false */ -/* jslint node: true */ -/* jshint -W061 */ -'use strict'; - -const WebSocket = require('ws'); -const querystring = require('querystring'); - -const MESSAGE_TYPES = { - MESSAGE: 0, - PING: 1, - PONG: 2, - CALLBACK: 3 -}; - -const DEBUG = false; - -function Socket(ws, sessionID, name) { - this.ws = ws; - const handlers = {}; - let lastPong = Date.now(); - let id = 0; - - this._name = name; - - // simulate interface of socket.io - this.conn = { - request: { sessionID } - }; - - this.id = sessionID; - - let pingInterval = setInterval(() => { - if (Date.now() - lastPong > 5000) { - ws.send(JSON.stringify([MESSAGE_TYPES.PING])); - } - if (Date.now() - lastPong > 15000) { - this.close(); - } - }, 5000); - - this.on = (name, cb) => { - if (cb) { - handlers[name] = handlers[name] || []; - handlers[name].push(cb); - } - }; - - this.off = (name, cb) => { - if (handlers[name]) { - const pos = handlers[name].indexOf(cb); - if (pos !== -1) { - handlers[name].splice(pos, 1); - if (!handlers[name].length) { - delete handlers[name]; - } - } - } - }; - - this.emit = (name, arg1, arg2, arg3, arg4, arg5) => { - id++; - if (arg1 === undefined && arg2 === undefined && arg3 === undefined && arg4 === undefined && arg5 === undefined) { - this.ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, id, name])); - } else if (arg2 === undefined && arg3 === undefined && arg4 === undefined && arg5 === undefined) { - this.ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, id, name, [arg1]])); - } else if (arg3 === undefined && arg4 === undefined && arg5 === undefined) { - this.ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, id, name, [arg1, arg2]])); - } else if (arg4 === undefined && arg5 === undefined) { - this.ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, id, name, [arg1, arg2, arg3]])); - } else if (arg5 === undefined) { - this.ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, id, name, [arg1, arg2, arg3, arg4]])); - } else { - this.ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, id, name, [arg1, arg2, arg3, arg4, arg5]])); - } - }; - - this.responseWithCallback = (name, id, arg1, arg2, arg3, arg4, arg5) => { - let args; - - // error cannot be converted normally, so try to use internal function for it - if (arg1 && arg1 instanceof Error) { - arg1 = arg1.toString(); - } - - if (arg1 === undefined && arg2 === undefined && arg3 === undefined && arg4 === undefined && arg5 === undefined) { - return ws.send(JSON.stringify([MESSAGE_TYPES.CALLBACK, id, name])); - } else if (arg2 === undefined && arg3 === undefined && arg4 === undefined && arg5 === undefined) { - args = [arg1]; - } else if (arg3 === undefined && arg4 === undefined && arg5 === undefined) { - args = [arg1, arg2]; - } else if (arg4 === undefined && arg5 === undefined) { - args = [arg1, arg2, arg3]; - } else if (arg5 === undefined) { - args = [arg1, arg2, arg3, arg4]; - } else { - args = [arg1, arg2, arg3, arg4, arg5]; - } - - ws.send(JSON.stringify([MESSAGE_TYPES.CALLBACK, id, name, args])); - }; - - this.withCallback = (name, id, args) => { - if (!args || !args.length) { - setImmediate(() => - handlers[name] && handlers[name].forEach(cb => cb.call(this, (arg1, arg2, arg3, arg4, arg5) => - this.responseWithCallback(name, id, arg1, arg2, arg3, arg4, arg5)))); - } else if (args.length === 1) { - setImmediate(() => - handlers[name] && handlers[name].forEach(cb => cb.call(this, args[0], (arg1, arg2, arg3, arg4, arg5) => - this.responseWithCallback(name, id, arg1, arg2, arg3, arg4, arg5)))); - } else if (args.length === 2) { - setImmediate(() => - handlers[name] && handlers[name].forEach(cb => cb.call(this, args[0], args[1], (arg1, arg2, arg3, arg4, arg5) => - this.responseWithCallback(name, id, arg1, arg2, arg3, arg4, arg5)))); - } else if (args.length === 3) { - setImmediate(() => - handlers[name] && handlers[name].forEach(cb => cb.call(this, args[0], args[1], args[2], (arg1, arg2, arg3, arg4, arg5) => - this.responseWithCallback(name, id, arg1, arg2, arg3, arg4, arg5)))); - } else if (args.length === 4) { - setImmediate(() => - handlers[name] && handlers[name].forEach(cb => cb.call(this, args[0], args[1], args[2], args[3], (arg1, arg2, arg3, arg4, arg5) => - this.responseWithCallback(name, id, arg1, arg2, arg3, arg4, arg5)))); - } else { - setImmediate(() => - handlers[name] && handlers[name].forEach(cb => cb.call(this, args[0], args[1], args[2], args[3], args[4], (arg1, arg2, arg3, arg4, arg5) => - this.responseWithCallback(name, id, arg1, arg2, arg3, arg4, arg5)))); - } - }; - - ws.on('message', (data, isBinary) => { - lastPong = Date.now(); - let message = isBinary ? data : data.toString(); - - if (!message || typeof message !== 'string') { - return console.error('Received invalid message: ' + JSON.stringify(message)); - } - try { - message = JSON.parse(message); - } catch (e) { - return console.error('Received invalid message: ' + JSON.stringify(message)); - } - const [type, id, name, args] = message; - - if (type === MESSAGE_TYPES.CALLBACK) { - DEBUG && console.log(name); - handlers[name] && this.withCallback(name, id, args); - } else - if (type === MESSAGE_TYPES.MESSAGE) { - DEBUG && console.log(name); - handlers[name] && setImmediate(() => handlers[name] && handlers[name].forEach(cb => cb.call(this, args[0], args[1], args[2], args[3], args[4]))); - } else if (type === MESSAGE_TYPES.PING) { - ws.send(JSON.stringify([MESSAGE_TYPES.PONG])); - } else if (type === MESSAGE_TYPES.PONG) { - // lastPong saved - } else { - console.log('Received unknown message type: ' + type); - } - }); - - this.close = () => { - pingInterval && clearInterval(pingInterval); - pingInterval = null; - - handlers.disconnect && handlers.disconnect.forEach(cb => cb.apply(this)); - - Object.keys(handlers).forEach(name => handlers[name] = undefined); - - try { - ws.close(); - } catch (e) { - // ignore - } - }; -} - -function SocketIO (server) { - const handlers = {}; - const run = []; - - const socketsList = []; - - const wss = new WebSocket.Server({ - server, - verifyClient: function (info, done) { - if (run.length) { - run.forEach(cb => cb(info.req, err => { - if (err) { - info.req._wsNotAuth = true; - } - done && done(true); - done = null; - })); - } else { - done && done(true); - done = null; - } - }, - perMessageDeflate: { - zlibDeflateOptions: { - chunkSize: 1024, - memLevel: 9, - level: 9 - }, - zlibInflateOptions: { - chunkSize: 16 * 1024 - }, - clientNoContextTakeover: true, - serverNoContextTakeover: true - } - }); - - wss.on('connection', (ws, request) => { - DEBUG && console.log('connected'); - - if (!request) { - console.error('Unexpected behaviour: request is NULL!'); - } - - if (request && request._wsNotAuth) { - const ip = request.headers['x-forwarded-for'] || - request.connection.remoteAddress || - request.socket.remoteAddress || - (request.connection.socket ? request.connection.socket.remoteAddress : null); - handlers.error && handlers.error.forEach(cb => cb('error', `authentication failed for ${ip}`)); - ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, 401, 'reauthenticate'])); - setTimeout(() => - ws && ws.destroy && ws.destroy(), 500); - } else { - let query; - - try { - if (request) { - const queryString = request.url.split('?')[1]; - query = querystring.parse(queryString || ''); - } - } catch (e) { - query = null; - } - - if (query && query.sid) { - const socket = new Socket(ws, request.sessionID || query.sid, query.name); - socket.query = query; - socketsList.push(socket); - this.sockets.engine.clientsCount = socketsList.length; - - ws.on('close', () => { - DEBUG && console.log('closed'); - let i; - for (i = 0; i < socketsList.length; i++) { - if (socketsList[i].ws === ws) { - socketsList[i].close(); - socketsList.splice(i, 1); - this.sockets.engine.clientsCount = socketsList.length; - return; - } - } - }); - - // install handlers - if (handlers.connection && handlers.connection.length) { - // we have a race condition here. - // If the user is not admin it will be requested for him the rights and no handlers will be installed. - // So we must be sure, that all event handlers are installed before sending ___ready___. - let timeout = setTimeout(() => { - timeout = null; - socket.emit('___ready___'); - console.warn('Sent ready, but not all handlers installed!'); - }, 1500); // TODO, This parameter must be configurable - - handlers.connection.forEach(cb => cb(socket, () => { - if (timeout) { - clearTimeout(timeout); - timeout = null; - // say to client we are ready - socket.emit('___ready___'); - } - })); - } else { - socket.emit('___ready___'); - } - } else { - if (request) { - const ip = request.headers['x-forwarded-for'] || - request.connection.remoteAddress || - request.socket.remoteAddress || - (request.connection.socket ? request.connection.socket.remoteAddress : null); - - handlers.error && handlers.error.forEach(cb => cb('error', 'No sid found from ' + ip)); - } else { - handlers.error && handlers.error.forEach(cb => cb('error', 'No sid found')); - } - - ws.send(JSON.stringify([MESSAGE_TYPES.MESSAGE, 501, 'error', ['invalid sid']])); - setTimeout(() => - ws && ws.destroy && ws.destroy(), 500); - } - } - }); - - this.on = (name, cb) => { - if (cb) { - handlers[name] = handlers[name] || []; - handlers[name].push(cb); - } - }; - - this.off = (name, cb) => { - if (handlers[name]) { - const pos = handlers[name].indexOf(cb); - if (pos !== -1) { - handlers[name].splice(pos, 1); - if (!handlers[name].length) { - delete handlers[name]; - } - } - } - }; - - this.sockets = { - connected: socketsList, - emit: (arg1, arg2, arg3, arg4, arg5) => - socketsList.forEach(socket => - socket.emit(arg1, arg2, arg3, arg4, arg5)), - engine: { - clientsCount: 0 - } - }; - - this.engine = this.sockets.engine; - - this.use = cb => { - run.push(cb); - return this; - }; - - this.ioBroker = true; -} - -module.exports = { - listen: server => new SocketIO(server) -}; diff --git a/main.js b/main.js index cf480b6..6485f17 100644 --- a/main.js +++ b/main.js @@ -95,7 +95,6 @@ function main() { // "bind": "0.0.0.0", // "::" //} function initWebServer(settings) { - const server = { app: null, server: null, diff --git a/package.json b/package.json index 6b76824..b6dd893 100644 --- a/package.json +++ b/package.json @@ -16,17 +16,18 @@ "url": "https://github.com/ioBroker/ioBroker.socketio" }, "dependencies": { + "@iobroker/adapter-core": "^2.5.1", "axios": "^0.25.0", "cookie-parser": "^1.4.6", - "passport": "^0.5.2", "express-session": "^1.17.2", - "@iobroker/adapter-core": "^2.5.1", - "ws": "^8.4.2" + "passport": "^0.5.2", + "socket.io": "^2.4.1" }, "devDependencies": { "@alcalzone/release-script": "^3.5.0", "@alcalzone/release-script-plugin-iobroker": "^3.5.1", "@alcalzone/release-script-plugin-license": "^3.5.0", + "socket.io-client": "^2.4.0", "gulp": "^4.0.2", "mocha": "^9.2.0", "chai": "^4.3.6" @@ -44,6 +45,7 @@ ], "scripts": { "test": "node node_modules/mocha/bin/mocha --exit", + "build": "node node_modules/gulp/bin/gulp.js", "release": "release-script", "release-patch": "release-script patch --yes", "release-minor": "release-script minor --yes",