node-red-contrib-remote 2.0.5 → 3.0.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
@@ -29,6 +29,17 @@ There is a help page describing how the the nodes work together and how to conne
29
29
  [Hilfe in Deutsch](https://www.remote-red.com/de/hilfe/)
30
30
 
31
31
 
32
+ ## Remote-RED Partner Programm
33
+
34
+ If you want to scale up, have a look at the Remote-RED Partner Programm. It is made for everyone who does not only use Node-RED for themselves, but builds solutions for others:
35
+
36
+ - developers of own IoT projects (Node-RED and also pure Linux projects)
37
+ - installers of smart home and control systems
38
+ - manufacturers and platforms looking for a white label solution
39
+
40
+ As a partner you offer your customers encrypted access to their dashboards, push notifications and geofencing triggers - without developing your own app and without running your own server infrastructure.
41
+
42
+
32
43
  ## Contact
33
44
 
34
45
  You will find more information on [www.remote-red-com](https://www.remote-red.com). You can contact me by mail through info@remote-red.com.
@@ -36,6 +47,9 @@ You will find more information on [www.remote-red-com](https://www.remote-red.co
36
47
 
37
48
  ## Version History
38
49
 
50
+ Version 3.0.0
51
+ - Support for the Remote-RED Partner Programm
52
+
39
53
  Version 2.0.5
40
54
  - Improved reconnect for Starlink users
41
55
 
@@ -16,7 +16,13 @@
16
16
  "region_dev": "Entwicklung",
17
17
  "region_desc": "Der Standort kann nicht mehr geändert werden, sobald eine App registriert wurde.",
18
18
  "change_info": "Damit Änderungen aktiv werden führe einen Redeploy durch. Starte danach die App neu oder aktualisiere die Liste der Instanzen, indem Du die Liste nach unten ziehst.",
19
- "backup_info": "Diese Konfig-Node wurde aus einem Backup wiederhergestellt. Daher sind sicherheitsrelevante Informationen nicht enthalten. Bitte löschen diese Konfig-Node (über das Zahnrad Icon rechts oben) und die Verbindungen in Deinen Remote-RED Apps. Lege eine neue Konfig-Node an, verbinde diese neu mit den Apps und wähle diese neue Konfig-Node in allen davon abhängigen Nodes aus."
19
+ "backup_info": "Diese Konfig-Node wurde aus einem Backup wiederhergestellt. Daher sind sicherheitsrelevante Informationen nicht enthalten. Bitte löschen diese Konfig-Node (über das Zahnrad Icon rechts oben) und die Verbindungen in Deinen Remote-RED Apps. Lege eine neue Konfig-Node an, verbinde diese neu mit den Apps und wähle diese neue Konfig-Node in allen davon abhängigen Nodes aus.",
20
+ "partner_toggle": "Ich bin Teilnehmer am Remote-RED Partner Programm",
21
+ "customerhash": "CustomerHash",
22
+ "customerkey": "CustomerKey",
23
+ "customerkey_desc": "Der CustomerKey wird nur einmalig zur Registrierung verwendet und nicht gespeichert.",
24
+ "customerreference": "Kunden-Referenz (optional)",
25
+ "customerreference_desc": "Z.B. Seriennummer oder Endkunden-Nummer, max. 100 Zeichen. Dient der Zuordnung dieser Instanz im Partner-Portal und ist nachträglich nicht mehr änderbar."
20
26
  },
21
27
  "actions" : {
22
28
  "register_app": "Remote-RED App verbinden",
@@ -34,6 +40,12 @@
34
40
  "privacypolicyurl": "https://www.remote-red.com/de/datenschutz",
35
41
  "termsurl": "https://www.remote-red.com/de/nutzung"
36
42
  },
43
+ "partner": {
44
+ "title": "Remote-RED Partner Programm",
45
+ "info1": "Das Remote-RED Partner Programm richtet sich an Hersteller und Integratoren, die Remote-RED in eigene Produkte einbetten und über das Remote-RED Partner Portal eigene Kontingente an Instanzen verwalten und abrechnen. Falls Du Teilnehmer bist, kannst Du hier Deinen CustomerHash und CustomerKey eintragen, um diese Instanz Deinem Partner-Konto zuzuordnen. ",
46
+ "info1_readonly": "Diese Instanz ist bereits registriert und einem Partner-Konto zugeordnet. Die Zuordnung kann nachträglich nicht mehr geändert werden. Verwaltet wird die Instanz im Remote-RED Partner Portal. ",
47
+ "link": "Zum Remote-RED Partner Portal"
48
+ },
37
49
  "help": {
38
50
  "title": "Hilfe",
39
51
  "para1": "Pro Access-Node erstellt Du eine entsprechende Config-Node. In dieser wird hinterlegt, mit welchem Host, Port und URL die Verbindung stattfindet. Die Vorgabewerte zeigen als Beispiel das Dashboard. Es ist aber auch möglich weitere Seiten aus dem lokalen Netzwerk zu konfigurieren, insofern der Server auf dem Node-RED installiert ist darauf zugreifen kann.",
@@ -16,7 +16,13 @@
16
16
  "region_dev": "Development host",
17
17
  "region_desc": "The region can´t be changed after registering an app.",
18
18
  "change_info": "To apply changes, first carry out a redeploy. Then restart the app or refresh the list of instances by dragging the list down.",
19
- "backup_info": "This config node was restored from a backup. Therefore security relevant information are not included. Please delete this config-node (via the gear icon at the top right) and the connections in your Remote-RED apps. Create a new config-node, connect it to the apps and select this new config node in all dependent nodes."
19
+ "backup_info": "This config node was restored from a backup. Therefore security relevant information are not included. Please delete this config-node (via the gear icon at the top right) and the connections in your Remote-RED apps. Create a new config-node, connect it to the apps and select this new config node in all dependent nodes.",
20
+ "partner_toggle": "I'm a participant of the Remote-RED Partner Program",
21
+ "customerhash": "CustomerHash",
22
+ "customerkey": "CustomerKey",
23
+ "customerkey_desc": "The CustomerKey is only used once during registration and is not stored.",
24
+ "customerreference": "Customer reference (optional)",
25
+ "customerreference_desc": "E.g. serial number or end customer number, max. 100 characters. Used to identify this instance in the Partner Portal and cannot be changed afterwards."
20
26
  },
21
27
  "actions" : {
22
28
  "register_app": "Connect Remote-RED App",
@@ -34,6 +40,12 @@
34
40
  "privacypolicyurl": "https://www.remote-red.com/en/privacypolicy",
35
41
  "termsurl": "https://www.remote-red.com/en/terms"
36
42
  },
43
+ "partner": {
44
+ "title": "Remote-RED Partner Program",
45
+ "info1": "The Remote-RED Partner Program is aimed at manufacturers and integrators who embed Remote-RED into their own products and manage and bill their own instance quotas via the Remote-RED Partner Portal. If you are a participant, you can enter your CustomerHash and CustomerKey here to assign this instance to your partner account. ",
46
+ "info1_readonly": "This instance is already registered and assigned to a partner account. The assignment cannot be changed afterwards. The instance is managed in the Remote-RED Partner Portal. ",
47
+ "link": "Go to the Remote-RED Partner Portal"
48
+ },
37
49
  "help": {
38
50
  "title": "Help",
39
51
  "para1": "For each Access Node you create a corresponding Config Node. In this Config Node you define with which host, port and URL the connection will be established. The default values shows the dashboard as an example. It is also possible to configure other pages from the local network, as long as the Node-RED server can access them.",
@@ -75,7 +75,7 @@ module.exports = function(RED) {
75
75
  });
76
76
  } catch (e) {
77
77
  // TODO: Error: socket hang up
78
- node.error('startSSH error: ' + error);
78
+ node.error('startSSH error: ' + e);
79
79
  }
80
80
  }
81
81
 
@@ -169,6 +169,18 @@ module.exports = function(RED) {
169
169
  });
170
170
  }
171
171
 
172
+ function scheduleCheckServing(node, delay) {
173
+ // Only one checkServing timer per node: cancel a pending one before scheduling
174
+ clearTimeout(node.checkservingtimeout);
175
+ node.checkservingtimeout = setTimeout(checkServing, delay, node);
176
+ }
177
+
178
+ function scheduleTryConnect(node, delay) {
179
+ // Only one tryConnect timer per node: cancel a pending one before scheduling
180
+ clearTimeout(node.tryconnecttimeout);
181
+ node.tryconnecttimeout = setTimeout(tryConnect, delay, node);
182
+ }
183
+
172
184
  async function tryConnect(node) {
173
185
  // Request new instance slot and connect ssh
174
186
  try {
@@ -178,7 +190,7 @@ module.exports = function(RED) {
178
190
  }
179
191
 
180
192
  // Create timer to check if ssh process still serving in 10 seconds
181
- node.checkservingtimeout = setTimeout(checkServing, 1000*10, node);
193
+ scheduleCheckServing(node, 1000*10);
182
194
  }
183
195
 
184
196
  function checkServing(node) {
@@ -194,13 +206,13 @@ module.exports = function(RED) {
194
206
  } else if (node.errorcounter >= 4) {
195
207
  interval = 1000*50;
196
208
  }
197
- node.tryconnecttimeout = setTimeout(tryConnect, interval, node);
209
+ scheduleTryConnect(node, interval);
198
210
  } else {
199
211
  // Running > Reset error counter
200
212
  node.errorcounter = 0;
201
213
 
202
214
  // Schedule timer to check if still serving
203
- node.checkservingtimeout = setTimeout(checkServing, 1000*10, node);
215
+ scheduleCheckServing(node, 1000*10);
204
216
  }
205
217
  }
206
218
 
@@ -11,8 +11,7 @@
11
11
  instancehash: {value:""},
12
12
  server: {value:""},
13
13
  region: {value:"de"},
14
- customerhash: {value:""},
15
- customerkey: {value:""}
14
+ customerhash: {value:""}
16
15
  },
17
16
  credentials: {
18
17
  instanceauth: {type:"text"}
@@ -26,10 +25,32 @@
26
25
  document.getElementById('remoteInstanceInputs').style.visibility = 'collapse';
27
26
 
28
27
  // Deactivate region if already registered
29
- if (document.getElementById('node-config-input-instancehash').value != "") {
28
+ const alreadyRegistered = document.getElementById('node-config-input-instancehash').value != "";
29
+ if (alreadyRegistered) {
30
30
  document.getElementById('node-config-input-region').disabled = true;
31
31
  }
32
32
 
33
+ // Partner-Bereich: aufklappbar, Toggle togglet Sichtbarkeit
34
+ document.getElementById('node-config-input-showpartner').onchange = function() {
35
+ togglePartnerSection(this.checked);
36
+ };
37
+ // Bereits ein customerhash gesetzt? Dann direkt aufgeklappt anzeigen.
38
+ const hasCustomerhash = document.getElementById('node-config-input-customerhash').value != "";
39
+ if (hasCustomerhash) {
40
+ document.getElementById('node-config-input-showpartner').checked = true;
41
+ }
42
+ togglePartnerSection(hasCustomerhash);
43
+
44
+ // Instanz schon registriert? Partner-Zuordnung ist dann nicht mehr änderbar.
45
+ if (alreadyRegistered) {
46
+ document.getElementById('node-config-input-showpartner').disabled = true;
47
+ document.getElementById('node-config-input-customerhash').disabled = true;
48
+ document.getElementById('customerkeyRow').style.display = 'none';
49
+ document.getElementById('customerreferenceRow').style.display = 'none';
50
+ document.getElementById('partnerInfoEditable').style.display = 'none';
51
+ document.getElementById('partnerInfoReadonly').style.display = '';
52
+ }
53
+
33
54
  // Insert legal link urls
34
55
  setTimeout(insertLinkUrls, 250);
35
56
 
@@ -82,6 +103,18 @@
82
103
  document.getElementById('legalTermsLink').setAttribute('href', document.getElementById('terms_url_template').innerHTML);
83
104
  }
84
105
 
106
+ function togglePartnerSection(show) {
107
+ // Shows/hides the Remote-RED Partner Programm section
108
+ const section = document.getElementById('partnerSection');
109
+ if (show) {
110
+ section.style.removeProperty('visibility');
111
+ section.style.removeProperty('max-height');
112
+ } else {
113
+ section.style.visibility = 'collapse';
114
+ section.style.maxHeight = '0px';
115
+ }
116
+ }
117
+
85
118
  function updateLocalhostInfo() {
86
119
  // Gives infos about localhost, maybe hides it.
87
120
  if (document.getElementById('node-config-input-host').value.toLowerCase() == 'localhost') {
@@ -103,7 +136,18 @@
103
136
  function registerInstance() {
104
137
  // Request InstanceHash when empty
105
138
  const region = document.getElementById('node-config-input-region').value;
106
- $.getJSON('contrib-remote/requestInstanceHash/' + region + '/0/0', function(data) {
139
+ const customerhash = document.getElementById('node-config-input-customerhash').value || '0';
140
+ const customerkey = document.getElementById('node-config-input-customerkeyinput').value || '0';
141
+ const customerreference = document.getElementById('node-config-input-customerreferenceinput').value || '';
142
+ let requestUrl = 'contrib-remote/requestInstanceHash/' + region + '/' + encodeURIComponent(customerhash) + '/' + encodeURIComponent(customerkey);
143
+ if (customerreference !== '') {
144
+ requestUrl += '?customerreference=' + encodeURIComponent(customerreference);
145
+ }
146
+ $.getJSON(requestUrl, function(data) {
147
+ // CustomerKey und CustomerReference werden nur einmalig zur Registrierung benoetigt - danach aus dem UI entfernen.
148
+ document.getElementById('node-config-input-customerkeyinput').value = '';
149
+ document.getElementById('node-config-input-customerreferenceinput').value = '';
150
+
107
151
  if ( data.error == undefined ) {
108
152
  // Fill UI
109
153
  document.getElementById('node-config-input-instancehash').value = data.instancehash;
@@ -267,6 +311,41 @@
267
311
  </div>
268
312
  <label><i class="fa fa-info-circle"></i> <span data-i18n="remote-config.label.region_desc"></label>
269
313
 
314
+ <br>
315
+ <br>
316
+ <div class="form-row">
317
+ <input type="checkbox" id="node-config-input-showpartner" style="display:inline-block; width:22px; vertical-align:top;">
318
+ <label for="node-config-input-showpartner" style="width:auto;" data-i18n="remote-config.label.partner_toggle"></label>
319
+ </div>
320
+ <div id="partnerSection" style="visibility: collapse; max-height: 0px;">
321
+ <div id="partnerInfo" style="max-width: 460px; border-width: 1px; border-style: dashed; border-color: #666; padding: 10px; margin-bottom: 10px;">
322
+ <label data-i18n="remote-config.partner.title" style="font-weight: bold;"></label>
323
+ <label id="partnerInfoEditable" data-i18n="remote-config.partner.info1"></label>
324
+ <label id="partnerInfoReadonly" data-i18n="remote-config.partner.info1_readonly" style="display: none;"></label>
325
+ <a id="partnerPortalLink" href="https://portal.remote-red.com" target="_blank"><i><label data-i18n="remote-config.partner.link" style="display: inline; color: #AD1626;"></label></i></a>
326
+ </div>
327
+ <div class="form-row">
328
+ <label for="node-config-input-customerhash"><span data-i18n="remote-config.label.customerhash"></span></label>
329
+ <input type="text" id="node-config-input-customerhash" placeholder="">
330
+ </div>
331
+ <div id="customerkeyRow">
332
+ <div class="form-row">
333
+ <label for="node-config-input-customerkeyinput"><span data-i18n="remote-config.label.customerkey"></span></label>
334
+ <input type="password" id="node-config-input-customerkeyinput" placeholder="">
335
+ </div>
336
+ <label><i class="fa fa-info-circle"></i> <span data-i18n="remote-config.label.customerkey_desc"></label>
337
+ <br>
338
+ </div>
339
+ <div id="customerreferenceRow">
340
+ <div class="form-row">
341
+ <label for="node-config-input-customerreferenceinput"><span data-i18n="remote-config.label.customerreference"></span></label>
342
+ <input type="text" id="node-config-input-customerreferenceinput" placeholder="" maxlength="100">
343
+ </div>
344
+ <label><i class="fa fa-info-circle"></i> <span data-i18n="remote-config.label.customerreference_desc"></label>
345
+ <br>
346
+ </div>
347
+ </div>
348
+
270
349
  <br>
271
350
  <button id="registerRemoteAppButton" type="button" class="red-ui-button" onclick="registerButtonClicked()">
272
351
  <span id="registerRemoteAppButtonText" data-i18n="remote-config.actions.register_app">
@@ -5,6 +5,7 @@ module.exports = function(RED) {
5
5
  const dns = require('dns');
6
6
  const dnsPromises = dns.promises;
7
7
  const fs = require('fs');
8
+ const path = require('path');
8
9
  var QRCode = require('qrcode');
9
10
 
10
11
  function RemoteConfigNode(n) {
@@ -18,6 +19,7 @@ module.exports = function(RED) {
18
19
  this.server = n.server;
19
20
  this.instanceauth = this.credentials.instanceauth;
20
21
  this.region = n.region;
22
+ this.customerhash = n.customerhash;
21
23
  }
22
24
 
23
25
  RED.nodes.registerType("remote-config",RemoteConfigNode, {
@@ -53,14 +55,12 @@ module.exports = function(RED) {
53
55
  .then(res => {
54
56
  const v4 = res.some(e => e.family === 4);
55
57
  const v6 = res.some(e => e.family === 6);
56
- testResults.push({type: 'DNS', test: `DNS lookup ${host}`, result: getErrorMessage(error)});
58
+ testResults.push({type: 'DNS', test: `DNS lookup ${host}`, result: `OK (${v4 ? 'IPv4' : ''}${v4 && v6 ? ', ' : ''}${v6 ? 'IPv6' : ''})`});
57
59
  console.log(res);
58
- // testResults.push({test: `DNS lookup ${host}`, result: res.alive ? `${res.time}ms` : 'Error'});
59
60
  })
60
61
  .catch(error => {
61
62
  console.log(error);
62
63
  console.log(`dns resolve ${host}: ${getErrorMessage(error)}`);
63
- // console.log(error);
64
64
  testResults.push({type: 'DNS', test: `DNS lookup ${host}`, result: getErrorMessage(error)});
65
65
  });
66
66
  });
@@ -129,12 +129,19 @@ module.exports = function(RED) {
129
129
  url = 'https://contact-' + req.params.regionorserver + '.remote-red.com/instanceHashRequest';
130
130
  }
131
131
 
132
- // Call API
133
- axiosInstance.post(url, {
132
+ // Build request body; customerreference is optional (query param, backwards compatible
133
+ // with older CLI/node versions that never send it, PARTNER-PORTAL-KONZEPT Kap. 8.3 pt. 7)
134
+ const postData = {
134
135
  'customerhash': req.params.customerhash,
135
136
  'customerkey': req.params.customerkey,
136
137
  'version': commons.getNodeVersion()
137
- })
138
+ };
139
+ if (req.query.customerreference !== undefined && req.query.customerreference !== '') {
140
+ postData.customerreference = req.query.customerreference;
141
+ }
142
+
143
+ // Call API
144
+ axiosInstance.post(url, postData)
138
145
  .then(response => {
139
146
  res.json(response.data);
140
147
  })
@@ -207,7 +214,8 @@ module.exports = function(RED) {
207
214
 
208
215
  RED.httpAdmin.get("/contrib-remote/getResouceFile/:filename", RED.auth.needsPermission('remote-config.read'), function(req,res) {
209
216
  // Sends a file as Base64
210
- const fileBase64 = fs.readFileSync(__dirname + '/resources/' + req.params.filename, {encoding: 'base64'});
217
+ const safeName = path.basename(req.params.filename);
218
+ const fileBase64 = fs.readFileSync(__dirname + '/resources/' + safeName, {encoding: 'base64'});
211
219
  res.json({ 'filedata': fileBase64 });
212
220
  });
213
221
 
@@ -75,7 +75,7 @@ module.exports = function(RED) {
75
75
  });
76
76
  } else {
77
77
  // To big...
78
- node.error("xxxThe message exceeded 3600 bytes. Can´t send.");
78
+ node.error("The message exceeded 3600 bytes. Can´t send.");
79
79
 
80
80
  // Output status if configured so
81
81
  if ( config.output == 2 ) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-remote",
3
- "version": "2.0.5",
3
+ "version": "3.0.0",
4
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",