node-red-contrib-remote 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Remote-RED
2
2
 
3
- Remote-RED is an ecosystem to bring remote access and push notifications to Node-RED. It consists of several parts:
3
+ Remote-RED is an ecosystem to bring remote access, push notification and geofencing to Node-RED. There are also additional functions like directly answer on a notification and homescreen widgets. It consists of several parts:
4
4
  - node-red-contrib-remote: The Node-RED nodes of Remote-RED. Published in this repro.
5
5
  - Remote-RED servers: Several servers used for proxying the remote access traffic and sending push notifications.
6
6
  - Remote-RED apps: Apps to access the services published by the Remote-RED remote-access node and receiving the push notifications of the remote-notification node. Available or Android, iOS and iPadOS.
@@ -36,6 +36,13 @@ You will find more information on [www.remote-red-com](https://www.remote-red.co
36
36
 
37
37
  ## Version History
38
38
 
39
+ Version 1.5.0
40
+ - Geofencing! You can add geofences in the apps. Entering and leaving them will trigger a message on the new output of the remote access node.
41
+ - Adding server location in Asia.
42
+ - New instances will have the base url '/ui' again.
43
+ - Error with "Multiple requests" after a missing internet connection fixed.
44
+ - iOS App: Links with target '_blank' will be redirected to iOS.
45
+
39
46
  Version 1.4.0
40
47
  - In addition to the QR code, a link is now generated to add an instance in the app.
41
48
  - Sending notifications and questions is prevented if msg.playload.send === false.
@@ -17,7 +17,8 @@
17
17
  "commerror": "Fehler bei der Kommunikation mit dem Server.",
18
18
  "noconfig": "Keine Konfiguration gefunden.",
19
19
  "incompleteconfig": "Konfiguration unvollständig.",
20
- "backupconfig": "Konfiguration aus Backup."
20
+ "backupconfig": "Konfiguration aus Backup.",
21
+ "banned": "Die Instanz wurde deaktiviert. Möglicherweise aufgrund einer DDOS-Attacke. Wenn Sie dieses System nicht missbrauchen, erstelle bitte eine neuen Konfig Node, um Remote-RED wieder zu verwenden. Andernfalls suchen Sie nach falschen Weiterleitungen oder Proxy Fehlern. Diese IP wird für 10 Minuten gesperrt."
21
22
  },
22
23
  "help": {
23
24
  "title": "Hilfe",
@@ -12,6 +12,7 @@
12
12
  "region": "Standort Server",
13
13
  "region_us": "Amerika (USA)",
14
14
  "region_de": "Europa (Deutschland)",
15
+ "region_sg": "Asien (Singapur)",
15
16
  "region_dev": "Entwicklung",
16
17
  "region_desc": "Der Standort kann nicht mehr geändert werden, sobald eine App registriert wurde.",
17
18
  "change_info": "Wenn Du Einstellungen änderst, musst Du die App neu verbinden.",
@@ -17,7 +17,8 @@
17
17
  "commerror": "Error communicating with server.",
18
18
  "noconfig": "No configuration found.",
19
19
  "incompleteconfig": "Configuration incomplete.",
20
- "backupconfig": "Configuration from backup."
20
+ "backupconfig": "Configuration from backup.",
21
+ "banned": "Instance is deactivated. Maybe due DDOS attacks. If you are not missusing this system, please create new config node to use Remote-RED again. Otherwise look for incorrect redirects or such errors. Banning IP for 10 minutes."
21
22
  },
22
23
  "help": {
23
24
  "title": "Help",
@@ -12,6 +12,7 @@
12
12
  "region": "Server location",
13
13
  "region_us": "America (USA)",
14
14
  "region_de": "Europe (Germany)",
15
+ "region_sg": "Asia (Singapur)",
15
16
  "region_dev": "Development host",
16
17
  "region_desc": "The region can´t be changed after registering an app.",
17
18
  "change_info": "If you change settings, you need to reconnect the app.",
@@ -8,10 +8,8 @@
8
8
  verbose: {value:0}
9
9
  },
10
10
  inputs: 0,
11
- outputs: 1,
12
- outputLabels: ["action output"],
13
- // outputs: 2,
14
- // outputLabels: ["action output", "geofence output"],
11
+ outputs: 2,
12
+ outputLabels: ["action output", "geofence output"],
15
13
  icon: "font-awesome/fa-mobile",
16
14
  label: function() {
17
15
  return this.name || "remote access";
@@ -4,6 +4,7 @@ module.exports = function(RED) {
4
4
  const os = require("os");
5
5
  let sshprocess = undefined
6
6
  let statustext = ''
7
+ let instanceIsBanned = false
7
8
 
8
9
  function startSSH(node, server, port) {
9
10
  try {
@@ -18,7 +19,7 @@ module.exports = function(RED) {
18
19
  if ( host === 'localhost' && os.platform() === 'win32' ) {
19
20
  host = '127.0.0.1'
20
21
  }
21
- //node.log('ssh -o StrictHostKeyChecking=no -R ' + port.toString() + ':' + host + ':' + node.confignode.port.toString() + ' forward@proxy-' + server + ' -N');
22
+ // node.log('ssh -o StrictHostKeyChecking=no -R ' + port.toString() + ':' + host + ':' + node.confignode.port.toString() + ' forward@proxy-' + server + ' -N');
22
23
  var sshparameters = ['-o StrictHostKeyChecking=no', '-R', port.toString() + ':' + host + ':' + node.confignode.port.toString(), 'forward@proxy-' + server, '-N'];
23
24
  if ( node.verbose ) {
24
25
  sshparameters.push('-v');
@@ -36,6 +37,9 @@ module.exports = function(RED) {
36
37
 
37
38
  sshprocess.stderr.on('data', (data) => {
38
39
  logSSHBuffer(node, data, 'ssh process stderr');
40
+ if ( data.toString().includes('Connection timed out')) {
41
+ node.error(`SSH connection timeout. Please check if port 22 is open for outgoing connections.`);
42
+ }
39
43
  });
40
44
 
41
45
  sshprocess.on('close', (code, signal) => {
@@ -89,6 +93,11 @@ module.exports = function(RED) {
89
93
  }
90
94
 
91
95
  function requestInstanceSlot(node) {
96
+ // Is this instance banned?
97
+ if ( instanceIsBanned ) {
98
+ return;
99
+ }
100
+
92
101
  // Call API to retrive server and port.
93
102
  const axiosInstance = commons.createAxiosInstance();
94
103
  axiosInstance.post(`https://api-${node.confignode.server}/instanceSlotRequest`, {
@@ -105,10 +114,22 @@ module.exports = function(RED) {
105
114
  startSSH(node, node.confignode.server, port);
106
115
  })
107
116
  .catch((error) => {
108
- node.error('requestInstanceSlot: ' + error);
109
- if ( error.response && error.response.data && error.response.data.message ) {
110
- node.error(`${error.response.data.message}`);
117
+ // Log error
118
+ node.error('requestInstanceSlot: ' + commons.getNetworkErrorString(error))
119
+ if ( commons.getNetworkErrorCustomString(error) !== undefined) {
120
+ node.error(commons.getNetworkErrorCustomString(error));
111
121
  }
122
+
123
+ // Wenn gebannt -> Merken
124
+ if ( error.response && error.response.status ) {
125
+ if ( error.response.status === 403 ) {
126
+ setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.banned"});
127
+ instanceIsBanned = true;
128
+ return;
129
+ }
130
+ }
131
+
132
+ // Set status
112
133
  setStatus(node, {fill:"red",shape:"dot",text:"remote-access.status.commerror"});
113
134
  return;
114
135
  });
@@ -183,10 +204,10 @@ module.exports = function(RED) {
183
204
  }
184
205
  })
185
206
  .catch((error) => {
186
- // Error on api call > Just log
187
- node.error('heartbeat: ' + error);
188
- if ( error.response && error.response.data && error.response.data.message ) {
189
- node.error(`${error.response.data.message}`);
207
+ // Error on api call > Log error
208
+ node.error('heartbeat: ' + commons.getNetworkErrorString(error))
209
+ if ( commons.getNetworkErrorCustomString(error) !== undefined) {
210
+ node.error(commons.getNetworkErrorCustomString(error));
190
211
  }
191
212
  });
192
213
  }
@@ -17,7 +17,7 @@ module.exports = {
17
17
  }
18
18
  }
19
19
  });
20
- return axios.create({ httpsAgent: httpsAgent });
20
+ return axios.create({ httpsAgent: httpsAgent, timeout: 5000 });
21
21
  },
22
22
 
23
23
  getNodeVersion: function() {
@@ -35,6 +35,27 @@ module.exports = {
35
35
  node.error(`Error evaluating value: ${e}`)
36
36
  }
37
37
  return evalValue;
38
+ },
39
+
40
+ getNetworkErrorString: function(error) {
41
+ // Trys to get a error message
42
+ let errorString = `` + error;
43
+ if ( error.response && error.response.data && error.response.data.message ) {
44
+ errorString = `${error.response.data.message}`;
45
+ }
46
+ return errorString;
47
+ },
48
+
49
+ getNetworkErrorCustomString: function(error) {
50
+ // Custom error messages for common errors
51
+ let errorString = undefined;
52
+ if ( error.code === 'ECONNABORTED' ) {
53
+ errorString = `Error during https call. Please check Internet connection on your Node-RED server. Please check if a firewall blocks outgoing port 443.`;
54
+ }
55
+ if ( error.code === 'EAI_AGAIN' ) {
56
+ errorString = `Error during DNS queries. Please check Internet connection on your Node-RED server. Please check if a firewall blocks your DNS queries.`;
57
+ }
58
+ return errorString;
38
59
  }
39
60
 
40
61
  }
@@ -103,6 +103,9 @@
103
103
  } else {
104
104
  // Show error
105
105
  alert('Error while registering instance: ' + data.error);
106
+
107
+ // Enable button again
108
+ document.getElementById('registerRemoteAppButton').disabled = false;
106
109
  }
107
110
  });
108
111
  }
@@ -214,6 +217,7 @@
214
217
  <select id="node-config-input-region">
215
218
  <option value="us" data-i18n="remote-config.label.region_us"></option>
216
219
  <option value="de" data-i18n="remote-config.label.region_de"></option>
220
+ <option value="sg" data-i18n="remote-config.label.region_sg"></option>
217
221
  <!-- <option value="dev" data-i18n="remote-config.label.region_dev"></option> -->
218
222
  </select>
219
223
  </div>
@@ -27,7 +27,7 @@ module.exports = function(RED) {
27
27
  // Return the internal IP and the mountpath
28
28
  const ipData = {
29
29
  'ipv4': internalIp.v4.sync(),
30
- 'baseurl': RED.httpNode.mountpath + ((RED.settings.ui !== undefined && RED.settings.ui.path !== undefined) ? RED.settings.ui.path : ''),
30
+ 'baseurl': RED.httpNode.mountpath + ((RED.settings.ui !== undefined && RED.settings.ui.path !== undefined) ? RED.settings.ui.path : 'ui'),
31
31
  'port': (RED.settings.uiPort !== undefined) ? String(RED.settings.uiPort) : '1880'
32
32
  }
33
33
  console.log(`${JSON.stringify(ipData)}`);
@@ -48,6 +48,9 @@ module.exports = function(RED) {
48
48
  if ( error.response && error.response.data && error.response.data.message ) {
49
49
  errorMessage = errorMessage + " / " + error.response.data.message;
50
50
  }
51
+ if ( commons.getNetworkErrorCustomString(error) !== undefined) {
52
+ errorMessage = commons.getNetworkErrorCustomString(error);
53
+ }
51
54
  res.json({ 'error': errorMessage });
52
55
  });
53
56
  });
@@ -97,6 +100,9 @@ module.exports = function(RED) {
97
100
  if ( error.response && error.response.data && error.response.data.message ) {
98
101
  errorMessage = errorMessage + " / " + error.response.data.message;
99
102
  }
103
+ if ( commons.getNetworkErrorCustomString(error) !== undefined) {
104
+ errorMessage = commons.getNetworkErrorCustomString(error);
105
+ }
100
106
  res.json({ 'error': errorMessage });
101
107
  });
102
108
  });
@@ -18,7 +18,7 @@ module.exports = function(RED) {
18
18
  // Act on incomming messages
19
19
  node.on('input', function(msg) {
20
20
  if (node.confignode != undefined) {
21
- if (msg.payload.send === false) {
21
+ if (msg.payload !== undefined && msg.payload.send === false) {
22
22
  node.log(`Notification not send (msg.payload.send = false).`)
23
23
  return;
24
24
  }
@@ -63,7 +63,11 @@ module.exports = function(RED) {
63
63
  }
64
64
  })
65
65
  .catch((error) => {
66
- node.error("ERROR: " + error);
66
+ // Log error
67
+ node.error('sendNotification: ' + commons.getNetworkErrorString(error))
68
+ if ( commons.getNetworkErrorCustomString(error) !== undefined) {
69
+ node.error(commons.getNetworkErrorCustomString(error));
70
+ }
67
71
 
68
72
  // Output status if configured so
69
73
  if ( config.output == 2 ) {
@@ -18,7 +18,7 @@ module.exports = function(RED) {
18
18
  // Act on incomming messages
19
19
  node.on('input', function(msg) {
20
20
  if (node.confignode != undefined) {
21
- if (msg.payload.send === false) {
21
+ if (msg.payload !== undefined && msg.payload.send === false) {
22
22
  node.log(`Question not send (msg.payload.send = false).`)
23
23
  return;
24
24
  }
@@ -77,7 +77,11 @@ module.exports = function(RED) {
77
77
  node.debug(`Question send successfull`)
78
78
  })
79
79
  .catch((error) => {
80
- node.error("ERROR: " + error);
80
+ // Log error
81
+ node.error('sendNotification: ' + commons.getNetworkErrorString(error))
82
+ if ( commons.getNetworkErrorCustomString(error) !== undefined) {
83
+ node.error(commons.getNetworkErrorCustomString(error));
84
+ }
81
85
 
82
86
  // Output Error
83
87
  const msg = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "node-red-contrib-remote",
3
- "version": "1.4.0",
4
- "description": "Remote services for Node-RED including remote access, push notifications and questions through push notifications.",
3
+ "version": "1.5.0",
4
+ "description": "Remote-RED is an ecosystem to bring remote access, push notification and geofencing to Node-RED. There are also additional functions like directly answer on a notification and homescreen widgets.",
5
5
  "author": "Thorsten Heilmann",
6
6
  "license": "GPL-3.0",
7
7
  "node-red": {