Merge branch 'Ylianst:master' into dockerrewrite

This commit is contained in:
dselen 2025-04-25 13:23:30 +02:00 committed by GitHub
commit 39395c9ac7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 6455 additions and 6058 deletions

Binary file not shown.

View File

@ -148,7 +148,7 @@ function linux_identifiers()
// Fetch Storage Info
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write("lshw -class disk | tr '\\n' '`' | awk '" + '{ len=split($0,lines,"*"); printf "["; for(i=2;i<=len;++i) { model=""; caption=""; size=""; clen=split(lines[i],item,"`"); for(j=2;j<clen;++j) { split(item[j],tokens,":"); split(tokens[1],key," "); if(key[1]=="description") { caption=substr(tokens[2],2); } if(key[1]=="product") { model=substr(tokens[2],2); } if(key[1]=="size") { size=substr(tokens[2],2); } } if(model=="") { model=caption; } if(caption!="" || model!="") { printf "%s{\\"Caption\\":\\"%s\\",\\"Model\\":\\"%s\\",\\"Size\\":\\"%s\\"}",(i==2?"":","),caption,model,size; } } printf "]"; }\'\nexit\n');
child.stdin.write("lshw -class disk -disable network | tr '\\n' '`' | awk '" + '{ len=split($0,lines,"*"); printf "["; for(i=2;i<=len;++i) { model=""; caption=""; size=""; clen=split(lines[i],item,"`"); for(j=2;j<clen;++j) { split(item[j],tokens,":"); split(tokens[1],key," "); if(key[1]=="description") { caption=substr(tokens[2],2); } if(key[1]=="product") { model=substr(tokens[2],2); } if(key[1]=="size") { size=substr(tokens[2],2); } } if(model=="") { model=caption; } if(caption!="" || model!="") { printf "%s{\\"Caption\\":\\"%s\\",\\"Model\\":\\"%s\\",\\"Size\\":\\"%s\\"}",(i==2?"":","),caption,model,size; } } printf "]"; }\'\nexit\n');
child.waitExit();
try { identifiers['storage_devices'] = JSON.parse(child.stdout.str.trim()); } catch (xx) { }
child = null;

View File

@ -170,8 +170,8 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
// TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF
const TLSSocket = require('tls').TLSSocket;
const tlsoptions = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
if (obj.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
const tlsoptions = { minVersion: 'TLSv1', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
// if (obj.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
const tlsock = new TLSSocket(ser, tlsoptions);
tlsock.on('error', function (err) { Debug(1, "CIRA TLS Connection Error ", err); });
tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); ws._socket.resume(); });
@ -228,8 +228,8 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
obj.forwardclient.setEncoding('binary');
} else {
// If TLS is going to be used, setup a TLS socket
var tlsoptions = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
if (obj.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
var tlsoptions = { minVersion: 'TLSv1', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
// if (obj.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
obj.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () {
// The TLS connection method is the same as TCP, but located a bit differently.
Debug(2, 'TLS Intel AMT transport connected to ' + node.host + ':' + port + '.');

View File

@ -236,8 +236,8 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
if (state == 0) { obj.xxOnSocketClosed(); }
if (state == 2) {
// TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF
var options = { socket: ser, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
if (obj.xtlsMethod == 1) { options.secureProtocol = 'TLSv1_method'; }
var options = { minVersion: 'TLSv1', socket: ser, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
// if (obj.xtlsMethod == 1) { options.secureProtocol = 'TLSv1_method'; }
if (obj.xtlsoptions) {
if (obj.xtlsoptions.ca) { options.ca = obj.xtlsoptions.ca; }
if (obj.xtlsoptions.cert) { options.cert = obj.xtlsoptions.cert; }
@ -274,8 +274,8 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
} else {
// Direct connect with TLS
var options = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
if (obj.xtlsMethod != 0) { options.secureProtocol = 'TLSv1_method'; }
var options = { minVersion: 'TLSv1', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
// if (obj.xtlsMethod != 0) { options.secureProtocol = 'TLSv1_method'; }
if (obj.xtlsoptions) {
if (obj.xtlsoptions.ca) { options.ca = obj.xtlsoptions.ca; }
if (obj.xtlsoptions.cert) { options.cert = obj.xtlsoptions.cert; }

View File

@ -387,8 +387,8 @@ module.exports.CreateAmtScanner = function (parent) {
} else {
// Connect using TLS, we will switch from default TLS to TLS1-only and back if we get a connection error to support older Intel AMT.
if (scaninfo.tlsoption == null) { scaninfo.tlsoption = 0; }
const tlsOptions = { rejectUnauthorized: false, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE };
if (scaninfo.tlsoption == 1) { tlsOptions.secureProtocol = 'TLSv1_method'; }
const tlsOptions = { minVersion: 'TLSv1', rejectUnauthorized: false, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION };
// if (scaninfo.tlsoption == 1) { tlsOptions.secureProtocol = 'TLSv1_method'; }
client = obj.tls.connect(port, host, tlsOptions, function () { this.write('GET / HTTP/1.1\r\nhost: ' + host + '\r\n\r\n'); });
}
client.scaninfo = scaninfo;

2
db.js
View File

@ -3661,7 +3661,7 @@ module.exports.CreateDB = function (parent, func) {
let mesg = 'Zipbackup failed (' + obj.backupStatus.toString(2).slice(-8) + '), deleting incomplete backup: ' + obj.newAutoBackupFile;
if (func) { func(mesg) }
else { parent.addServerWarning(mesg, true ) };
if (fs.existsSync(obj.newAutoBackupFile)) { fs.unlink(obj.newAutoBackupFile, function (err) { console.error('Failed to clean up backupfile: ' + err.message) }) };
if (fs.existsSync(obj.newAutoBackupFile)) { fs.unlink(obj.newAutoBackupFile, function (err) { if (err) {console.error('Failed to clean up backupfile: ' + err.message)} }) };
};
if (obj.databaseType != DB_NEDB) {
//remove dump archive file, because zipped and otherwise fills up

View File

@ -99,3 +99,50 @@ Now that MeshCentral customizes and signs the agent, you can set that value to a
}
}
```
## External Signing Job
The externalsignjob feature allows you to perform additional operations on the agent after MeshCentral completes its code signing process. This is particularly useful for:
1. Using hardware security tokens for signing
2. Performing signing on a separate server or cloud host
3. Archiving signed agents
4. Adding additional security measures
The externalsignjob is called after MeshCentral completes its entire code signing process, including:
- Resource modification
- Digital signature application
- Timestamp application (if configured)
To use this feature, add the following to your config.json:
```json
"settings": {
"externalsignjob": "path/to/your/script.bat"
}
```
The script will receive the path to the agent as its first argument. Here are example scripts:
### Batch File Example
```batch
@echo off
Echo External Signing Job
signtool sign /tr http://timestamp.sectigo.com /td SHA256 /fd SHA256 /a /v /f path/to/your/signing.cer /csp "eToken Base Cryptographic Provider" /k "[{{MyPassword}}]=PrivateKeyContainerName" "%~1"
```
### PowerShell Example
```powershell
$file = $args[0]
signtool sign /tr http://timestamp.sectigo.com /td SHA256 /fd SHA256 /a /v /f path/to/your/signing.cer /csp "eToken Base Cryptographic Provider" /k "[{{MyPassword}}]=PrivateKeyContainerName" $file
```
The externalsignjob can be used for more than just signing. For example, you could:
1. Archive signed agents to a secure location
2. Upload signed agents to a distribution server
3. Perform additional security checks
4. Add custom metadata or watermarks
5. Integrate with your organization's build pipeline
Note: The script must return a success exit code (0) for the process to be considered successful. Any non-zero exit code will be treated as a failure and will be logged.

View File

@ -1095,6 +1095,7 @@ First we will start with the MeshCentral configuration, here is a minimal config
"domains": {
"": {
"certUrl": "https://127.0.0.1:443/"
"AgentConfig": [ "webSocketMaskOverride=1" ]
}
}
}

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]">Click here to download the MeshCentral Assistant for Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]">Click here to download the MeshCentral Assistant for Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ For Linux, cut & paste the following in a terminal to install the agent:
~<area-assistant>
For MeshCentral Assistant on Windows, nagivate to the following link to complete the process:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Kliknite ovdje da preuzmete MeshCentral Assistant za Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Kliknite ovdje da preuzmete MeshCentral Assistant za Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Za Linux, izrežite i zalijepite sljedeće u terminal da biste instalirali agent
~<area-assistant>
Za MeshCentral Assistant na Windows-u, idite na sljedeću vezu da dovršite proces:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Kliknutím sem stáhnete MeshCentral Assistant pro Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Kliknutím sem stáhnete MeshCentral Assistant pro Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ V případě systému Linux vyjměte a vložte do terminálu a nainstalujte agen
~<area-assistant>
Pro MeshCentral Assistant v systému Windows přejděte na následující odkaz a dokončete proces:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Klik her for at downloade MeshCentral Assistant til Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Klik her for at downloade MeshCentral Assistant til Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ For Linux skal du klippe og indsætte følgende i en terminal for at installere
~<area-assistant>
For MeshCentral Assistant på Windows skal du gå til følgende link for at fuldføre processen:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Klicken Sie hier, um den MeshCentral-Assistenten für Windows herunterzuladen.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Klicken Sie hier, um den MeshCentral-Assistenten für Windows herunterzuladen.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Schneiden Sie unter Linux Folgendes aus und fügen Sie es in ein Terminal ein, u
~<area-assistant>
Navigieren Sie für MeshCentral Assistant unter Windows zum folgenden Link, um den Vorgang abzuschließen:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Haga clic aquí para descargar el Asistente de MeshCentral para Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Haga clic aquí para descargar el Asistente de MeshCentral para Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Para Linux, copia y pega lo siguiente en la terminal para instalar el agente:
~<area-assistant>
Para el Asistente de MeshCentral en Windows, navegue hasta el siguiente enlace para completar el proceso:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Napsauta tätä ladataksesi MeshCentral Assistant for Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Napsauta tätä ladataksesi MeshCentral Assistant for Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Linux: leikkaa ja liitä seuraava päätelaitteeseen agentin asentamiseksi:
~<area-assistant>
Jos käytät MeshCentral Assistantia Windowsissa, siirry seuraavaan linkkiin prosessin viimeistelemiseksi:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Cliquez ici pour télécharger l'assistant Meshcentral pour Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Cliquez ici pour télécharger l'assistant Meshcentral pour Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Pour Linux, copiez et collez les éléments suivants dans un terminal pour insta
~<area-assistant>
Pour l'assistant MeshCentral sous Windows, cliquez sur le lien suivant pour compléter le processus :
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">विंडोज के लिए मेशसेंट्रल असिस्टेंट डाउनलोड करने के लिए यहां क्लिक करें।</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">विंडोज के लिए मेशसेंट्रल असिस्टेंट डाउनलोड करने के लिए यहां क्लिक करें।</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Apple OSX के लिए, इस प्रक्रिया को पूर
~<area-assistant>
विंडोज़ पर मेशसेंट्रल असिस्टेंट के लिए, प्रक्रिया को पूरा करने के लिए निम्न लिंक पर जाएँ:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Kattintson ide a MeshCentral Assistant for Windows letöltéséhez.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Kattintson ide a MeshCentral Assistant for Windows letöltéséhez.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Linux esetén az Agent telepítéséhez vágja ki és illessze be egy terminálb
~<area-assistant>
Windows rendszeren futó MeshCentral Assistant esetén menjen a következő hivatkozásra a folyamat befejezéséhez:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Fare clic qui per scaricare MeshCentral Assistant per Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Fare clic qui per scaricare MeshCentral Assistant per Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Per Linux, taglia e incolla quanto segue in un terminale per installare l'agente
~<area-assistant>
Per MeshCentral Assistant su Windows, accedere al seguente collegamento per completare il processo:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Windows용 MeshCentral Assistant를 다운로드하려면 여기를 클릭하십시오.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Windows용 MeshCentral Assistant를 다운로드하려면 여기를 클릭하십시오.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Linuxの場合は、ターミナルで以下をカットアンドペーストし
~<area-assistant>
Windows용 MeshCentral Assistant의 경우 다음 링크로 이동하여 프로세스를 완료하십시오.
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Windows용 MeshCentral Assistant를 다운로드하려면 여기를 클릭하십시오.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Windows용 MeshCentral Assistant를 다운로드하려면 여기를 클릭하십시오.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Linux의 경우, 다음을 잘라내어 터미널에 붙여 넣어 에이전트
~<area-assistant>
Windows용 MeshCentral Assistant의 경우 다음 링크로 이동하여 프로세스를 완료하십시오.
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Klik hier om de MeshCentral Assistant voor Windows te downloaden.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Klik hier om de MeshCentral Assistant voor Windows te downloaden.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Voor Linux, knip het volgende en plak dit in een terminal om de agent te install
~<area-assistant>
Voor MeshCentral Assistant voor Windows navigeert u naar de volgende link om het proces te voltooien:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Kliknij tutaj by pobrać Asystenta MeshCentral dla Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Kliknij tutaj by pobrać Asystenta MeshCentral dla Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ W systemie Linuks, wytnij i wklej poniższe polecenia w terminalu, aby zainstalo
~<area-assistant>
W przypadku Asystenta MeshCentral w Windows, przejdź do tego linku aby zakończyć proces:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Clique aqui para baixar o Mesh Central Assistant para Windows</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Clique aqui para baixar o Mesh Central Assistant para Windows</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Para Linux, recorte e cole o seguinte em um terminal para instalar o agente:
~<area-assistant>
Para o MeshCentral Assistant no Windows, abre o seguinte link para completar o processo:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Clique aqui para baixar o Assistente MeshCentral para Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Clique aqui para baixar o Assistente MeshCentral para Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Para Linux, recorte e cole o seguinte em um terminal para instalar o agente:
~<area-assistant>
Para o MeshCentral Assistant no Windows, navegue até o seguinte link para concluir o processo:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Нажмите здесь, чтобы загрузить MeshCentral Assistant для Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Нажмите здесь, чтобы загрузить MeshCentral Assistant для Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@
~<area-assistant>
Для MeshCentral Assistant под Windows перейдите по следующей ссылке, чтобы завершить процесс:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Klicka här för att ladda ner MeshCentral Assistant för Windows.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Klicka här för att ladda ner MeshCentral Assistant för Windows.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ För Linux, klipp och klistra in följande i en terminal för att installera age
~<area-assistant>
För MeshCentral Assistant på Windows, gå till följande länk för att slutföra processen:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">Windows için MeshCentral Assistant'ı indirmek için buraya tıklayın.</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">Windows için MeshCentral Assistant'ı indirmek için buraya tıklayın.</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@ Linux için, aracıyı yüklemek için aşağıdakileri kesip bir terminale yap
~<area-assistant>
Windows'ta MeshCentral Assistant için işlemi tamamlamak üzere aşağıdaki bağlantıya gidin:
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">单击此处下载适用于 Windows 的 MeshCentral 助手。</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">单击此处下载适用于 Windows 的 MeshCentral 助手。</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@
~<area-assistant>
对于 Windows 上的 MeshCentral Assistant导航到以下链接以完成该过程
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -34,7 +34,7 @@
</area-linux>
<area-assistant>
<p style="margin-left:30px">
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]">單擊此處下載適用於 Windows 的 MeshCentral 助手。</a>
<a href="[[[SERVERURL]]]/meshagents?id=10006&amp;meshid=[[[MESHIDHEX]]]&amp;tag=mailto:[[[EMAIL]]]&amp;ac=[[[ASSISTANTTYPE]]]">單擊此處下載適用於 Windows 的 MeshCentral 助手。</a>
</p>
</area-assistant>
<area-link>

View File

@ -29,7 +29,7 @@
~<area-assistant>
對於 Windows 上的 MeshCentral Assistant導航到以下鏈接以完成該過程
~
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]
~[[[SERVERURL]]]/meshagents?id=10006&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&ac=[[[ASSISTANTTYPE]]]
~
~</area-assistant>
~<area-link>

View File

@ -66,7 +66,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
if (obj.parent.config.letsencrypt.email == null) { obj.configErr = "Let's Encrypt email address not specified."; parent.addServerWarning(obj.configErr); obj.log("WARNING: " + obj.configErr); func(certs); return; }
if ((obj.parent.redirserver == null) || ((typeof obj.parent.config.settings.rediraliasport === 'number') && (obj.parent.config.settings.rediraliasport !== 80)) || ((obj.parent.config.settings.rediraliasport == null) && (obj.parent.redirserver.port !== 80))) { obj.configErr = "Redirection web server must be active on port 80 for Let's Encrypt to work."; parent.addServerWarning(obj.configErr); obj.log("WARNING: " + obj.configErr); func(certs); return; }
if (obj.redirWebServerHooked !== true) { obj.configErr = "Redirection web server not setup for Let's Encrypt to work."; parent.addServerWarning(obj.configErr); obj.log("WARNING: " + obj.configErr); func(certs); return; }
if ((obj.parent.config.letsencrypt.rsakeysize != null) && (obj.parent.config.letsencrypt.rsakeysize !== 2048) && (obj.parent.config.letsencrypt.rsakeysize !== 3072)) { obj.configErr = "Invalid Let's Encrypt certificate key size, must be 2048 or 3072."; parent.addServerWarning(obj.configErr); obj.log("WARNING: " + obj.configErr); func(certs); return; }
if ((obj.parent.config.letsencrypt.rsakeysize != null) && (obj.parent.config.letsencrypt.rsakeysize !== 2048) && (obj.parent.config.letsencrypt.rsakeysize !== 3072) && (obj.parent.config.letsencrypt.rsakeysize !== 4096)) { obj.configErr = "Invalid Let's Encrypt certificate key size, must be 2048, 3072 or 4096."; parent.addServerWarning(obj.configErr); obj.log("WARNING: " + obj.configErr); func(certs); return; }
if (obj.checkInterval == null) { obj.checkInterval = setInterval(obj.checkRenewCertificate, 86400000); } // Call certificate check every 24 hours.
obj.configOk = true;
@ -165,7 +165,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
// Create a private key
obj.log("Generating private key...");
acme.forge.createPrivateKey().then(function (accountKey) {
acme.forge.createPrivateKey(obj.parent.config.letsencrypt.rsakeysize != null ? obj.parent.config.letsencrypt.rsakeysize : 2048).then(function (accountKey) {
// Create the ACME client
obj.log("Setting up ACME client...");
@ -189,7 +189,7 @@ module.exports.CreateLetsEncrypt = function (parent) {
// Create Certificate Request (CSR)
obj.log("Creating certificate request...");
var certRequest = { commonName: obj.leDomains[0] };
var certRequest = { commonName: obj.leDomains[0], keySize: obj.parent.config.letsencrypt.rsakeysize != null ? obj.parent.config.letsencrypt.rsakeysize : 2048 };
if (obj.leDomains.length > 1) { certRequest.altNames = obj.leDomains; }
acme.forge.createCsr(certRequest).then(function (r) {
obj.csr = r[1];

View File

@ -546,7 +546,7 @@
},
"agentWsCompression": {
"type": "boolean",
"default": true,
"default": false,
"description": "Enables agent-side, websocket per-message deflate compression. wscompression must also be true for this to work."
},
"noAgentUpdate": {
@ -3892,6 +3892,11 @@
"default": false,
"description": "By default a test certificate will be obtained from Let's Encrypt. Setting \"zerossl\", will ignore this setting. Always start by getting a test certificate and make sure that works before setting this to true and obtaining a production certificate. Making too many bad requests for a production certificate will get you banned for a long period of time."
},
"rsaKeySize": {
"type": "integer",
"default": 2048,
"description": "The size of the RSA key to generate. The default is 2048 bits."
},
"nochecks": {
"type": "boolean",
"default": false,

View File

@ -3415,6 +3415,7 @@ function CreateMeshCentralServer(config, args) {
// Failed to sign agent
addServerWarning('Failed to sign \"' + agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname + '\": ' + err, 22, [agentSignedFunc.objx.meshAgentsArchitectureNumbers[agentSignedFunc.archid].localname, err]);
}
obj.callExternalSignJob(agentSignedFunc.signingArguments); // Call external signing job regardless of success or failure
if (--pendingOperations === 0) { agentSignedFunc.func(); }
}
pendingOperations++;
@ -3470,7 +3471,10 @@ function CreateMeshCentralServer(config, args) {
}
const signingArguments = { out: signeedagentpath, desc: signDesc, url: signUrl, time: timeStampUrl, proxy: timeStampProxy }; // Shallow clone
signingArguments.resChanges = resChanges;
obj.debug('main', "Code signing with arguments: " + JSON.stringify(signingArguments));
xagentSignedFunc.signingArguments = signingArguments; // Attach the signing arguments to the callback function
if (resChanges == false) {
// Sign the agent the simple way, without changing any resources.
originalAgent.sign(agentSignCertInfo, signingArguments, xagentSignedFunc);
@ -3479,16 +3483,40 @@ function CreateMeshCentralServer(config, args) {
// NOTE: This is experimental and could corupt the agent.
originalAgent.writeExecutable(signingArguments, agentSignCertInfo, xagentSignedFunc);
}
} else {
// Signed agent is already ok, use it.
originalAgent.close();
}
}
}
if (--pendingOperations === 0) { func(); }
}
obj.callExternalSignJob = function (signingArguments) {
if (obj.config.settings && !obj.config.settings.externalsignjob) {
return;
}
obj.debug('main', "External signing job called for file: " + signingArguments.out);
const { spawnSync } = require('child_process');
const signResult = spawnSync('"' + obj.config.settings.externalsignjob + '"', ['"' + signingArguments.out + '"'], {
encoding: 'utf-8',
shell: true,
stdio: 'inherit'
});
if (signResult.error || signResult.status !== 0) {
obj.debug('main', "External signing failed for file: " + signingArguments.out);
console.error("External signing failed for file: " + signingArguments.out);
return;
}
}
// Update the list of available mesh agents
obj.updateMeshAgentsTable = function (domain, func) {
// Check if a custom agent signing certificate is available

View File

@ -346,7 +346,7 @@ module.exports.CreateMeshMail = function (parent, domain) {
}
// Set all the template replacement options and generate the final email text (both in txt and html formats).
var options = { username: username, name: name, email: email, installflags: flags, msg: msg, meshid: meshid, meshidhex: meshid.split('/')[2], servername: domain.title ? domain.title : 'MeshCentral' };
var options = { username: username, name: name, email: email, installflags: flags, msg: msg, meshid: meshid, meshidhex: meshid.split('/')[2], servername: domain.title ? domain.title : 'MeshCentral', assistanttype: (domain.assistanttypeagentinvite ? domain.assistanttypeagentinvite : 0)};
if (loginkey != null) { options.urlargs1 = '?key=' + loginkey; options.urlargs2 = '&key=' + loginkey; } else { options.urlargs1 = ''; options.urlargs2 = ''; }
options.windows = ((os == 0) || (os == 1)) ? 1 : 0;
options.linux = ((os == 0) || (os == 2)) ? 1 : 0;

View File

@ -78,6 +78,72 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
}
}
// Record a new entry in a recording log
function recordingEntry (logfile, type, flags, data, func, tag) {
try {
if (logfile.text) {
// Text recording format
var out = '';
const utcDate = new Date(Date.now());
if (type == 1) {
// End of start
out = data + '\r\n' + utcDate.toUTCString() + ', ' + "<<<START>>>" + '\r\n';
} else if (type == 3) {
// End of log
out = new Date(Date.now() - 5000).toUTCString() + ', ' + "<<<END>>>" + '\r\n';
} else if (typeof data == 'string') {
// Log message
if (logfile.text == 1) {
out = utcDate.toUTCString() + ', ' + data + '\r\n';
} else if (logfile.text == 2) {
try {
var x = JSON.parse(data);
if (typeof x.action == 'string') {
if ((x.action == 'chat') && (typeof x.msg == 'string')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + x.msg + '\r\n'); }
else if ((x.action == 'file') && (typeof x.name == 'string') && (typeof x.size == 'number')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + "File Transfer" + ', \"' + x.name + '\" (' + x.size + ' ' + "bytes" + ')\r\n'); }
} else if (x.ctrlChannel == null) { out = utcDate.toUTCString() + ', ' + data + '\r\n'; }
} catch (ex) {
out = utcDate.toUTCString() + ', ' + data + '\r\n';
}
}
}
if (out != null) {
// Log this event
const block = Buffer.from(out);
require('fs').write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
logfile.size += block.length;
} else {
// Skip logging this.
func(logfile, tag);
}
} else {
// Binary recording format
if (typeof data == 'string') {
// String write
var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
header.writeInt16BE(type, 0); // Type (1 = Start, 2 = Network Data, 3 = End)
header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
header.writeInt32BE(blockData.length, 4); // Size
header.writeIntBE((type == 3 ? new Date(Date.now() - 5000) : new Date()), 10, 6); // Time
var block = Buffer.concat([header, blockData]);
require('fs').write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
logfile.size += block.length;
} else {
// Binary write
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
header.writeInt16BE(type, 0); // Type (1 = Start, 2 = Network Data)
header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
header.writeInt32BE(data.length, 4); // Size
header.writeIntBE((type == 3 ? new Date(Date.now() - 5000) : new Date()), 10, 6); // Time
var block = Buffer.concat([header, data]);
require('fs').write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
logfile.size += block.length;
}
}
} catch (ex) { console.log(ex); func(logfile, tag); }
}
module.exports.recordingEntry = recordingEntry;
function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
const currentTime = Date.now();
if (cookie) {
@ -123,6 +189,9 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
// Check if protocol is set in the cookie and if so replace req.query.p but only if its not already set or blank
if ((cookie != null) && (typeof cookie.p == 'number') && (obj.req.query.p === undefined || obj.req.query.p === "")) { obj.req.query.p = cookie.p; }
// Patch Messenger protocol to 200
if ((obj.id != null) && (obj.id.startsWith('meshmessenger/') == true)) { obj.req.query.p = 200; }
// Mesh Rights
const MESHRIGHT_EDITMESH = 1;
const MESHRIGHT_MANAGEUSERS = 2;
@ -512,6 +581,7 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
if (obj.req.query.p == 1) { msg = 'Started terminal session'; msgid = 14; }
else if (obj.req.query.p == 2) { msg = 'Started desktop session'; msgid = 15; }
else if (obj.req.query.p == 5) { msg = 'Started file management session'; msgid = 16; }
else if (obj.req.query.p == 200) { msg = 'Started messenger session'; msgid = 162; }
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: sessionUser._id, username: sessionUser.name, msgid: msgid, msgArgs: [obj.id, obj.peer.req.clientIp, req.clientIp], msg: msg + ' \"' + obj.id + '\" from ' + obj.peer.req.clientIp + ' to ' + req.clientIp, protocol: req.query.p, nodeid: req.query.nodeid };
if (obj.guestname) { event.guestname = obj.guestname; } else if (relayinfo.peer1.guestname) { event.guestname = relayinfo.peer1.guestname; } // If this is a sharing session, set the guest name here.
parent.parent.DispatchEvent(['*', sessionUser._id], obj, event);
@ -747,13 +817,14 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
recordingEntry(logfile, 3, 0, 'MeshCentralMCREC', function (logfile, tag) {
parent.parent.fs.closeSync(logfile.fd);
parent.parent.debug('relay', 'Relay: Finished recording to file: ' + tag.logfile.filename);
// Now that the recording file is closed, check if we need to index this file.
if (domain.sessionrecording.index && domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', tag.logfile.filename); }
// Compute session length
var sessionLength = null;
if (tag.logfile.startTime != null) { sessionLength = Math.round((Date.now() - tag.logfile.startTime) / 1000); }
if (tag.logfile.startTime != null) { sessionLength = Math.round((Date.now() - tag.logfile.startTime) / 1000) - 5; }
// Add a event entry about this recording
var basefile = parent.parent.path.basename(tag.logfile.filename);
@ -792,71 +863,6 @@ function CreateMeshRelayEx(parent, ws, req, domain, user, cookie) {
if (obj.pid != null) { parent.parent.RemoveAllEventDispatch(obj); }
}
// Record a new entry in a recording log
function recordingEntry(logfile, type, flags, data, func, tag) {
try {
if (logfile.text) {
// Text recording format
var out = '';
const utcDate = new Date(Date.now());
if (type == 1) {
// End of start
out = data + '\r\n' + utcDate.toUTCString() + ', ' + "<<<START>>>" + '\r\n';
} else if (type == 3) {
// End of log
out = utcDate.toUTCString() + ', ' + "<<<END>>>" + '\r\n';
} else if (typeof data == 'string') {
// Log message
if (logfile.text == 1) {
out = utcDate.toUTCString() + ', ' + data + '\r\n';
} else if (logfile.text == 2) {
try {
var x = JSON.parse(data);
if (typeof x.action == 'string') {
if ((x.action == 'chat') && (typeof x.msg == 'string')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + x.msg + '\r\n'); }
else if ((x.action == 'file') && (typeof x.name == 'string') && (typeof x.size == 'number')) { out = utcDate.toUTCString() + ', ' + (((flags & 2) ? '--> ' : '<-- ') + "File Transfer" + ', \"' + x.name + '\" (' + x.size + ' ' + "bytes" + ')\r\n'); }
} else if (x.ctrlChannel == null) { out = utcDate.toUTCString() + ', ' + data + '\r\n'; }
} catch (ex) {
out = utcDate.toUTCString() + ', ' + data + '\r\n';
}
}
}
if (out != null) {
// Log this event
const block = Buffer.from(out);
parent.parent.fs.write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
logfile.size += block.length;
} else {
// Skip logging this.
func(logfile, tag);
}
} else {
// Binary recording format
if (typeof data == 'string') {
// String write
var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
header.writeInt32BE(blockData.length, 4); // Size
header.writeIntBE(new Date(), 10, 6); // Time
var block = Buffer.concat([header, blockData]);
parent.parent.fs.write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
logfile.size += block.length;
} else {
// Binary write
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
header.writeInt32BE(data.length, 4); // Size
header.writeIntBE(new Date(), 10, 6); // Time
var block = Buffer.concat([header, data]);
parent.parent.fs.write(logfile.fd, block, 0, block.length, function () { func(logfile, tag); });
logfile.size += block.length;
}
}
} catch (ex) { console.log(ex); func(logfile, tag); }
}
// If this session has a expire time, setup the expire timer now.
setExpireTimer();

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "1.1.43",
"version": "1.1.44",
"keywords": [
"Remote Device Management",
"Remote Device Monitoring",

File diff suppressed because one or more lines are too long

View File

@ -735,7 +735,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
/*
Intel AMT only recognizes a small subset of keysym characters defined in the keysymdef.h so you dont need to
Intel AMT only recognizes a small subset of keysym characters defined in the keysymdef.h so you dont need to
implement all the languages (this is taken care by the USB Scancode Extension in RFB4.0 protocol).
The only subset recognized by the FW is the defined by the following sets : XK_LATIN1 , XK_MISCELLANY, XK_3270, XK_XKB_KEYS, XK_KATAKANA.
In addition to keysymdef.h symbols there are 6 japanese extra keys that we do support:
@ -1018,7 +1018,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.recordedData = [];
obj.recordedStart = Date.now();
obj.recordedSize = 0;
obj.recordedData.push(recordingEntry(1, 0, JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, time: new Date().toLocaleString(), protocol: 200, bpp: obj.bpp, graymode: obj.graymode, lowcolor: obj.lowcolor, screenSize: [obj.width, obj.height] }))); // Metadata, 200 = Midstream Intel AMT KVM
obj.recordedData.push(recordingEntry(1, 0, JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, time: new Date().toLocaleString(), protocol: 102, bpp: obj.bpp, graymode: obj.graymode, lowcolor: obj.lowcolor, screenSize: [obj.width, obj.height] }))); // Metadata, 102 = Midstream Intel AMT KVM
obj.DeskRecordServerInit = String.fromCharCode((obj.width >> 8), (obj.width & 0xFF), (obj.height >> 8), (obj.height & 0xFF)) + obj.DeskRecordServerInit.substring(4);
obj.recordedData.push(recordingEntry(2, 1, obj.DeskRecordServerInit)); // This is the server init command
obj.recordedData.push(recordingEntry(3, 0, atob(obj.CanvasId.toDataURL('image/png').split(',')[1]))); // Take a screen shot

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -5187,7 +5187,11 @@
if (i > 0) { su = u.substring(i + 1); }
su = EscapeHtml(su);
if (su.length > 15) { su = su.substring(0, 14) + '&#8230;'; }
return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
if (node.lusers && node.lusers.length > 0) {
return addKeyLinkConditional(EscapeHtml(su), EscapeHtml(u) + " " + "(" + "Locked" + ")", (node.lusers && node.lusers.indexOf(u) >= 0));
} else {
return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
}
}
function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
@ -8468,7 +8472,8 @@
x += '<div id=d2modenow>';
x += addHtmlValue("Expire Time", '<select id=d2inviteExpire style=float:right;width:250px>' + y + '</select>');
x += '</div><div id=d2moderange style=display:none>';
x += addHtmlValue("Time Range", '<input id=d2timeRangeSelector style=float:right;width:250px class=flatpickr type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlValue("Time Range Start", '<input id=d2timeRangeStartSelector style=float:right;width:250px class=flatpickr type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlValue("Time Range End", '<input id=d2timeRangeEndSelector style=float:right;width:250px class=flatpickr type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += '</div><div id=d2moderecurring style=display:none>';
x += addHtmlValue("Start Time", '<input id=d2timeStartSelector style=float:right;width:250px class=flatpickr type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlValue("Duration", '<select id=d2inviteDuration style=float:right;width:250px>' + z + '</select>');
@ -8480,9 +8485,18 @@
showShareDeviceValidate();
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
var rangeTime = flatpickr('#d2timeRangeSelector', { mode: 'range', enableTime: true, minDate: new Date(), defaultDate: [ new Date(), tomorrow ], minuteIncrement: 1 });
var startTime = flatpickr('#d2timeStartSelector', { enableTime: true, minDate: new Date(), defaultDate: new Date(), minuteIncrement: 1 });
xxdialogTag = { range: rangeTime, start: startTime };
var rangeStartTime = flatpickr('#d2timeRangeStartSelector', {
enableTime: true, minDate: new Date(), defaultDate: new Date(), minuteIncrement: 1, plugins: [new confirmDatePlugin({})],
onChange: function(selectedDates, dateStr, instance) {
rangeEndTime.set('minDate', dateStr);
if (rangeEndTime.selectedDates[0] && rangeEndTime.selectedDates[0] < selectedDates[0]) {
rangeEndTime.clear();
}
}
});
var rangeEndTime = flatpickr('#d2timeRangeEndSelector', { enableTime: true, minDate: new Date(), defaultDate: tomorrow, minuteIncrement: 1, plugins: [new confirmDatePlugin({})] });
var startTime = flatpickr('#d2timeStartSelector', { enableTime: true, minDate: new Date(), defaultDate: new Date(), minuteIncrement: 1, plugins: [new confirmDatePlugin({})] });
xxdialogTag = { rangeStart: rangeStartTime, rangeEnd: rangeEndTime, start: startTime };
}
function showShareDeviceValidate() {
@ -8525,7 +8539,7 @@
if (Q('d2timeRange').value == 0) {
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, expire: parseInt(Q('d2inviteExpire').value), consent: consent, viewOnly: viewOnly });
} else if (Q('d2timeRange').value == 1) {
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, start: Math.floor(tag.range.selectedDates[0].getTime() / 1000), end: Math.floor(tag.range.selectedDates[1].getTime() / 1000), consent: consent, viewOnly: viewOnly });
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, start: Math.floor(tag.rangeStart.selectedDates[0].getTime() / 1000), end: Math.floor(tag.rangeEnd.selectedDates[0].getTime() / 1000), consent: consent, viewOnly: viewOnly });
} else {
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, start: Math.floor(tag.start.selectedDates[0].getTime() / 1000), expire: parseInt(Q('d2inviteDuration').value), recurring: Q('d2timeRange').value - 1, consent: consent, viewOnly: viewOnly });
}
@ -9740,7 +9754,7 @@
var rdpflags = 0;
for (var i = 1; i < 10; i++) { if ((i != 5) && (Q('d7rdp' + i).checked)) { rdpflags |= (1 << (i - 1)); } }
desktopsettings.rdpflags = rdpflags;
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
putstore('desktopsettings', JSON.stringify(desktopsettings));
applyDesktopSettings();
updateDesktopButtons();
if (desktop) {
@ -15356,7 +15370,8 @@
158: "Displaying alert box, title=\"{0}\", message=\"{1}\"",
159: "Device Powered On",
160: "Enabled Duo two-factor authentication",
161: "Disabled Duo two-factor authentication"
161: "Disabled Duo two-factor authentication",
162: "Started messenger session \"{0}\" from {1} to {2}"
};
var eventsShortMessageId = {
@ -17404,7 +17419,7 @@
if (p52recordings != null) {
var recdate = null;
for (var i in p52recordings) {
var rec = p52recordings[i], rect = new Date(rec.time), day = printDate(rect);
var rec = p52recordings[i], rect = new Date(rec.startTime), day = printDate(rect);
if (day != recdate) { recdate = day; x += '<tr><td class=userTableHeader colspan=4>' + day; }
x += addRecordingHtml(i, rec);
}
@ -17422,7 +17437,7 @@
function addRecordingHtml(i, rec) {
var sessionLengthStr = '';
if (rec.lengthTime) { sessionLengthStr = pad2(Math.floor(rec.lengthTime / 3600)) + ':' + pad2(Math.floor((rec.lengthTime % 3600) / 60)) + ':' + pad2(Math.floor(rec.lengthTime % 60)); }
var sessionStartStr = printTime(new Date(rec.time));
var sessionStartStr = printTime(new Date(rec.startTime));
if (rec.sessionStart) { sessionStartStr = printTime(new Date(rec.sessionStart)); }
var sessionSize = '';
if (rec.size) { sessionSize = format("{0} Kb", Math.round(rec.size / 1024)); }
@ -17484,6 +17499,7 @@
if (rec.protocol == 5) { protocolStr = "Files"; }
if (rec.protocol == 100) { protocolStr = "Intel&reg; AMT WSMAN"; }
if (rec.protocol == 101) { protocolStr = "Intel&reg; AMT Redirection"; }
if (rec.protocol == 200) { protocolStr = "Messenger"; }
x += addHtmlValue4("Protocol", protocolStr);
}
x += addHtmlValue4("Status", (rec.present == 1)?"Present on server":"Not on server");
@ -17491,7 +17507,7 @@
if (rec.meshname) { x += addHtmlValue4("Device Group", EscapeHtml(rec.meshname)); }
if (rec.size) { x += addHtmlValue4("Size", format("{0} bytes", rec.size)); }
if (rec.startTime) { x += addHtmlValue4("Start Time", printTime(new Date(rec.startTime))); }
if (rec.time) { x += addHtmlValue4("End Time", printTime(new Date(rec.time))); }
if (rec.startTime && rec.lengthTime) { x += addHtmlValue4("End Time", printTime(new Date(rec.startTime + (rec.lengthTime * 1000)))); }
if (rec.lengthTime) { x += addHtmlValue4("Duration", pad2(Math.floor(rec.lengthTime / 3600)) + ':' + pad2(Math.floor((rec.lengthTime % 3600) / 60)) + ':' + pad2(Math.floor(rec.lengthTime % 60))); }
if (rec.multiplex == true) { x += addHtmlValue4("Multiplexor", "Enabled"); }
if (rec.userids) { for (var i in rec.userids) { x += addHtmlValue4("User", rec.userids[i].split('/')[2]); } }
@ -17661,7 +17677,8 @@
x += '</div>';
x += '<div id=d2timeRangeDiv style=display:none>';
x += addHtmlValue("Time Range", '<input id=d2timeRangeSelector style=float:right;width:250px class=flatpickr type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlValue("Time Range Start", '<input id=d2timeRangeStartSelector style=float:right;width:250px class=flatpickr type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlValue("Time Range End", '<input id=d2timeRangeEndSelector style=float:right;width:250px class=flatpickr type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += '</div>';
x += '<div id=d2showTrafficDiv style=display:none>';
@ -17673,8 +17690,17 @@
var lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);
var rangeTime = flatpickr('#d2timeRangeSelector', { mode: 'range', enableTime: true, maxDate: new Date(), defaultDate: [ lastWeek, new Date() ], minuteIncrement: 1 });
xxdialogTag = rangeTime;
var rangeStartTime = flatpickr('#d2timeRangeStartSelector', {
enableTime: true, maxDate: new Date(), defaultDate: lastWeek, minuteIncrement: 1, plugins: [new confirmDatePlugin({})],
onChange: function(selectedDates, dateStr, instance) {
rangeEndTime.set('minDate', dateStr);
if (rangeEndTime.selectedDates[0] && rangeEndTime.selectedDates[0] < selectedDates[0]) {
rangeEndTime.clear();
}
}
});
var rangeEndTime = flatpickr('#d2timeRangeEndSelector', { enableTime: true, maxDate: new Date(), defaultDate: new Date(), minuteIncrement: 1, plugins: [new confirmDatePlugin({})] });
xxdialogTag = { start: rangeStartTime, end: rangeEndTime };
}
function generateReportDialogValidate() {
@ -17689,8 +17715,8 @@
function generateReportDialogEx(b, tag) {
var start, end;
if (Q('d2timeRange').value == 0) {
end = Math.floor(tag.selectedDates[1].getTime() / 1000);
start = Math.floor(tag.selectedDates[0].getTime() / 1000);
end = Math.floor(tag.end.selectedDates[0].getTime() / 1000);
start = Math.floor(tag.start.selectedDates[0].getTime() / 1000);
} else {
end = Math.floor(new Date() / 1000);
start = new Date();

View File

@ -5696,7 +5696,11 @@
if (i > 0) { su = u.substring(i + 1); }
su = EscapeHtml(su);
if (su.length > 15) { su = su.substring(0, 14) + '&#8230;'; }
return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
if (node.lusers && node.lusers.length > 0) {
return addKeyLinkConditional(EscapeHtml(su), EscapeHtml(u) + " " + "(" + "Locked" + ")", (node.lusers && node.lusers.indexOf(u) >= 0));
} else {
return '<span title="' + EscapeHtml(u) + '">' + su + '</span>';
}
}
function autoConnectDesktops() { if (Q('autoConnectDesktopCheckbox').checked == true) { connectAllKvmFunction(); } }
@ -6628,17 +6632,29 @@
} else if (op == 107) {
// Edit tags
var x = "Perform batch device tag operation" + '<br /><br />';
x += addHtmlFormFloating("Operation", '<select id=d2deviceop class="form-select-sm me-2"><option value=1>' + "Add tags" + '</option><option value=2>' + "Set tags" + '</option><option value=3>' + "Remove tags" + '</option></select>');
x += addHtmlFormFloating("Tags", '<input id=dp10devicevalue class="form-control" maxlength=4096 placeholder="' + "Tag1, Tag2, Tag3" + '" />');
x += addHtmlFormFloating("Operation", '<select id=d2deviceop class="form-select"><option value=1>' + "Add tags" + '</option><option value=2>' + "Set tags" + '</option><option value=3>' + "Remove tags" + '</option></select>');
x += addHtmlFormFloating("Tags", '<select id=dp10devicevalue multiple class="form-control" maxlength=4096>');
// Get a list of all possible device tags
var allTags = [], y = '';
for (var i in nodes) { if (nodes[i].tags) { for (var j in nodes[i].tags) { if (allTags.indexOf(nodes[i].tags[j]) == -1) { allTags.push(nodes[i].tags[j]); } } } }
if (allTags.length > 0) {
allTags.sort();
for (var i in allTags) { y += '<span style=padding:4px;background-color:#BBB;border-radius:3px;cursor:pointer onclick=showEditNodeValueDialogAddTag("' + encodeURIComponentEx(allTags[i]) + '")>' + EscapeHtml(allTags[i]) + '</span> '; }
x += '<div style=margin-top:8px;width:370px;line-height:26px;max-height:160px;overflow-y:auto>' + y + '</div>';
for (var i in allTags) {
var tag = EscapeHtml(allTags[i]);
y += '<option>' + EscapeHtml(allTags[i]) + '</option>';
}
}
x += y + '</select>'
setModalContent('xxAddAgent', "Edit Device Tags", x);
$('#dp10devicevalue').select2({
theme: 'bootstrap-5',
width: $( this ).data( 'width' ) ? $( this ).data( 'width' ) : $( this ).hasClass( 'w-100' ) ? '100%' : 'style',
placeholder: "Tag1, Tag2, Tag3",
closeOnSelect: false,
allowClear: true,
tokenSeparators: [','],
tags: true
});
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => d2groupActionFunctionTagsExec());
} else if (op == 108) {
// Device notification
@ -6718,12 +6734,13 @@
}
function d2groupActionFunctionTagsExec() {
var chkNodeIds = getCheckedDevices(), op = Q('d2deviceop').value, optags = Q('dp10devicevalue').value;
var chkNodeIds = getCheckedDevices(), op = Q('d2deviceop').value, optags = [];
var tt = $('#dp10devicevalue').select2('data');
for (var i in tt) { optags.push(tt[i]['text'].trim()); }
if (op == 2) { // Set tags
for (var i in chkNodeIds) { meshserver.send({ action: 'changedevice', nodeid: chkNodeIds[i], tags: optags }); }
for (var i in chkNodeIds) { meshserver.send({ action: 'changedevice', nodeid: chkNodeIds[i], tags: optags.join(',') }); }
} else {
var taggroup = [];
optags = optags.split(',');
for (var i in optags) { var tname = optags[i].trim(); if ((tname.length > 0) && (tname.length < 64) && (taggroup.indexOf(tname) == -1)) { taggroup.push(tname); } }
for (var i in chkNodeIds) {
var nodeTags = null, tagChanges = false, n = getNodeFromId(chkNodeIds[i]);
@ -9161,7 +9178,8 @@
x += '<div id=d2modenow>';
x += addHtmlFormFloating("Expire Time", '<select id=d2inviteExpire class="form-select">' + y + '</select>');
x += '</div><div id=d2moderange style=display:none>';
x += addHtmlFormFloating("Time Range", '<input id=d2timeRangeSelector class="flatpickr form-select" type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlFormFloating("Time Range Start", '<input id=d2timeRangeStartSelector class="flatpickr form-select" type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlFormFloating("Time Range End", '<input id=d2timeRangeEndSelector class="flatpickr form-select" type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += '</div><div id=d2moderecurring style=display:none>';
x += addHtmlFormFloating("Start Time", '<input id=d2timeStartSelector class="flatpickr form-select" type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlFormFloating("Duration", '<select id=d2inviteDuration class="form-select">' + z + '</select>');
@ -9172,14 +9190,24 @@
xxdialogButtons = 3;
setModalContent('xxAddAgent', "Share Device", x);
showModal('xxAddAgentModal', 'idx_dlgOkButton', showShareDeviceEx);
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => showShareDeviceEx('', xxdialogTag));
showShareDeviceValidate();
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
var rangeTime = flatpickr('#d2timeRangeSelector', { mode: 'range', enableTime: true, minDate: new Date(), defaultDate: [new Date(), tomorrow], minuteIncrement: 1 });
var startTime = flatpickr('#d2timeStartSelector', { enableTime: true, minDate: new Date(), defaultDate: new Date(), minuteIncrement: 1 });
xxdialogTag = { range: rangeTime, start: startTime };
var rangeStartTime = flatpickr('#d2timeRangeStartSelector', {
enableTime: true, minDate: new Date(), defaultDate: new Date(), minuteIncrement: 1,
plugins: [new confirmDatePlugin({})],
onChange: function(selectedDates, dateStr, instance) {
rangeEndTime.set('minDate', dateStr);
if (rangeEndTime.selectedDates[0] && rangeEndTime.selectedDates[0] < selectedDates[0]) {
rangeEndTime.clear();
}
}
});
var rangeEndTime = flatpickr('#d2timeRangeEndSelector', { enableTime: true, minDate: tomorrow, defaultDate: tomorrow, minuteIncrement: 1, plugins: [new confirmDatePlugin({})] });
var startTime = flatpickr('#d2timeStartSelector', { enableTime: true, minDate: new Date(), defaultDate: new Date(), minuteIncrement: 1, plugins: [new confirmDatePlugin({})] });
xxdialogTag = { rangeStart: rangeStartTime, rangeEnd: rangeEndTime, start: startTime };
}
function showShareDeviceValidate() {
@ -9222,7 +9250,7 @@
if (Q('d2timeRange').value == 0) {
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, expire: parseInt(Q('d2inviteExpire').value), consent: consent, viewOnly: viewOnly });
} else if (Q('d2timeRange').value == 1) {
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, start: Math.floor(tag.range.selectedDates[0].getTime() / 1000), end: Math.floor(tag.range.selectedDates[1].getTime() / 1000), consent: consent, viewOnly: viewOnly });
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, start: Math.floor(tag.rangeStart.selectedDates[0].getTime() / 1000), end: Math.floor(tag.rangeEnd.selectedDates[0].getTime() / 1000), consent: consent, viewOnly: viewOnly });
} else {
meshserver.send({ action: 'createDeviceShareLink', nodeid: currentNode._id, guestname: Q('d2inviteName').value.trim(), p: q, start: Math.floor(tag.start.selectedDates[0].getTime() / 1000), expire: parseInt(Q('d2inviteDuration').value), recurring: Q('d2timeRange').value - 1, consent: consent, viewOnly: viewOnly });
}
@ -9815,13 +9843,12 @@
if (v == null) v = '';
if (mode == 3) {
// Get a list of all possible device tags
x = '<select id=dp10devicevalue multiple class="form-control" maxlength=' + showEditNodeValueDialog_modes4[mode] + ' class=form-control>';
x = '<select id=dp10devicevalue multiple maxlength=' + showEditNodeValueDialog_modes4[mode] + ' class=form-control>';
var allTags = [];
for (var i in nodes) { if (nodes[i].tags) { for (var j in nodes[i].tags) { if (allTags.indexOf(nodes[i].tags[j]) == -1) { allTags.push(nodes[i].tags[j]); } } } }
if (allTags.length > 0) {
allTags.sort();
for (var i in allTags) {
var tag = EscapeHtml(allTags[i]);
y += Array.isArray(v) && v.indexOf(allTags[i]) !== -1 ? '<option selected=selected>' + EscapeHtml(allTags[i]) + '</option>' : '<option>' + EscapeHtml(allTags[i]) + '</option>';
}
}
@ -9841,24 +9868,12 @@
setModalContent('xxAddAgent', "Edit Device", x);
if (Array.isArray(v)) { v = v.join(', '); }
Q('dp10devicevalue').value = v;
showModal('xxAddAgentModal', 'idx_dlgOkButton', function () {
showEditNodeValueDialogEx(3, mode);
});
}
p10editdevicevalueValidate();
showModal('xxAddAgentModal', 'idx_dlgOkButton', function () { showEditNodeValueDialogEx(3, mode); });
Q('dp10devicevalue').focus();
}
function showEditNodeValueDialogAddTag(t) {
var tt = Q('dp10devicevalue').value.split(','), t2 = [];
for (var i in tt) { t2.push(tt[i].trim()); }
if (t2.indexOf(t) >= 0) return;
Q('dp10devicevalue').value += ((Q('dp10devicevalue').value.length == 0) ? '' : ', ') + decodeURIComponent(t);
setTimeout(function () { Q('dp10devicevalue').selectionStart = Q('dp10devicevalue').selectionEnd = 90000; }, 0);
p10editdevicevalueValidate();
}
function showEditNodeValueDialogEx(button, mode) {
var tags = '';
var x = { action: 'changedevice', nodeid: currentNode._id };
@ -10506,7 +10521,7 @@
var rdpflags = 0;
for (var i = 1; i < 10; i++) { if ((i != 5) && (Q('d7rdp' + i).checked)) { rdpflags |= (1 << (i - 1)); } }
desktopsettings.rdpflags = rdpflags;
localStorage.setItem('desktopsettings', JSON.stringify(desktopsettings));
putstore('desktopsettings', JSON.stringify(desktopsettings));
applyDesktopSettings();
updateDesktopButtons();
if (desktop) {
@ -16510,7 +16525,8 @@
158: "Displaying alert box, title=\"{0}\", message=\"{1}\"",
159: "Device Powered On",
160: "Enabled Duo two-factor authentication",
161: "Disabled Duo two-factor authentication"
161: "Disabled Duo two-factor authentication",
162: "Started messenger session \"{0}\" from {1} to {2}"
};
var eventsShortMessageId = {
@ -18669,7 +18685,7 @@
if (p52recordings != null) {
var recdate = null;
for (var i in p52recordings) {
var rec = p52recordings[i], rect = new Date(rec.time), day = printDate(rect);
var rec = p52recordings[i], rect = new Date(rec.startTime), day = printDate(rect);
if (day != recdate) { recdate = day; x += '<tr><td class=userTableHeader colspan=4>' + day; }
x += addRecordingHtml(i, rec);
}
@ -18687,7 +18703,7 @@
function addRecordingHtml(i, rec) {
var sessionLengthStr = '';
if (rec.lengthTime) { sessionLengthStr = pad2(Math.floor(rec.lengthTime / 3600)) + ':' + pad2(Math.floor((rec.lengthTime % 3600) / 60)) + ':' + pad2(Math.floor(rec.lengthTime % 60)); }
var sessionStartStr = printTime(new Date(rec.time));
var sessionStartStr = printTime(new Date(rec.startTime));
if (rec.sessionStart) { sessionStartStr = printTime(new Date(rec.sessionStart)); }
var sessionSize = '';
if (rec.size) { sessionSize = format("{0} Kb", Math.round(rec.size / 1024)); }
@ -18749,6 +18765,7 @@
if (rec.protocol == 5) { protocolStr = "Files"; }
if (rec.protocol == 100) { protocolStr = "Intel&reg; AMT WSMAN"; }
if (rec.protocol == 101) { protocolStr = "Intel&reg; AMT Redirection"; }
if (rec.protocol == 200) { protocolStr = "Messenger"; }
x += addHtmlValue4("Protocol", protocolStr);
}
x += addHtmlValue4("Status", (rec.present == 1) ? "Present on server" : "Not on server");
@ -18756,7 +18773,7 @@
if (rec.meshname) { x += addHtmlValue4("Device Group", EscapeHtml(rec.meshname)); }
if (rec.size) { x += addHtmlValue4("Size", format("{0} bytes", rec.size)); }
if (rec.startTime) { x += addHtmlValue4("Start Time", printTime(new Date(rec.startTime))); }
if (rec.time) { x += addHtmlValue4("End Time", printTime(new Date(rec.time))); }
if (rec.startTime && rec.lengthTime) { x += addHtmlValue4("End Time", printTime(new Date(rec.startTime + (rec.lengthTime * 1000)))); }
if (rec.lengthTime) { x += addHtmlValue4("Duration", pad2(Math.floor(rec.lengthTime / 3600)) + ':' + pad2(Math.floor((rec.lengthTime % 3600) / 60)) + ':' + pad2(Math.floor(rec.lengthTime % 60))); }
if (rec.multiplex == true) { x += addHtmlValue4("Multiplexor", "Enabled"); }
if (rec.userids) { for (var i in rec.userids) { x += addHtmlValue4("User", rec.userids[i].split('/')[2]); } }
@ -18929,7 +18946,8 @@
x += '</div>';
x += '<div id=d2timeRangeDiv style=display:none>';
x += addHtmlFormFloating("Time Range", '<input id=d2timeRangeSelector class="flatpickr form-control" type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlFormFloating("Time Range Start", '<input id=d2timeRangeStartSelector class="flatpickr form-control" type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += addHtmlFormFloating("Time Range End", '<input id=d2timeRangeEndSelector class="flatpickr form-control" type="text" placeholder="' + "Select Date & Time..." + '" data-id="altinput">');
x += '</div>';
x += '<div id=d2showTrafficDiv style=display:none>';
@ -18937,13 +18955,22 @@
x += '</div>';
setModalContent('xxAddAgent', "Generate Report", x);
showModal('xxAddAgentModal', 'idx_dlgOkButton', generateReportDialogEx);
showModal('xxAddAgentModal', 'idx_dlgOkButton', () => generateReportDialogEx('', xxdialogTag));
generateReportDialogValidate();
var lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);
var rangeTime = flatpickr('#d2timeRangeSelector', { mode: 'range', enableTime: true, maxDate: new Date(), defaultDate: [lastWeek, new Date()], minuteIncrement: 1 });
xxdialogTag = rangeTime;
var rangeStartTime = flatpickr('#d2timeRangeStartSelector', {
enableTime: true, maxDate: new Date(), defaultDate: lastWeek, minuteIncrement: 1, plugins: [new confirmDatePlugin({})],
onChange: function(selectedDates, dateStr, instance) {
rangeEndTime.set('minDate', dateStr);
if (rangeEndTime.selectedDates[0] && rangeEndTime.selectedDates[0] < selectedDates[0]) {
rangeEndTime.clear();
}
}
});
var rangeEndTime = flatpickr('#d2timeRangeEndSelector', { enableTime: true, maxDate: new Date(), defaultDate: new Date(), minuteIncrement: 1, plugins: [new confirmDatePlugin({})] });
xxdialogTag = { rangeStart: rangeStartTime, rangeEnd: rangeEndTime };
}
function generateReportDialogValidate() {
@ -18958,8 +18985,8 @@
function generateReportDialogEx(b, tag) {
var start, end;
if (Q('d2timeRange').value == 0) {
end = Math.floor(tag.selectedDates[1].getTime() / 1000);
start = Math.floor(tag.selectedDates[0].getTime() / 1000);
end = Math.floor(tag.rangeEnd.selectedDates[0].getTime() / 1000);
start = Math.floor(tag.rangeStart.selectedDates[0].getTime() / 1000);
} else {
end = Math.floor(new Date() / 1000);
start = new Date();

View File

@ -403,7 +403,8 @@
else if (p == 2) { p = "MeshCentral Desktop"; }
else if (p == 100) { p = "Intel&reg; AMT WSMAN"; }
else if (p == 101) { p = "Intel&reg; AMT Redirection"; }
else if (p == 200) { p = "Intel&reg; AMT KVM"; }
else if ((p == 102) || (p == 200 && recFileMetadata.bpp != null)) { p = "Intel&reg; AMT KVM"; }
else if (p == 200) { p = "MeshMessenger"; }
x += addInfoNoEsc("Protocol", p);
}
var encQualityStr = "2 byte-per-pixel";
@ -469,9 +470,9 @@
amtDesktop.Start();
deskAdjust();
}
else if (recFileMetadata.protocol == 200) {
else if (recFileMetadata.protocol == 102 || (recFileMetadata.protocol == 200 && recFileMetadata.bpp != null)) {
// Intel AMT Midstream KVM
recFileProtocol = 200;
recFileProtocol = 102;
x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
QE('PlayButton', true);
QE('PauseButton', false);
@ -576,14 +577,14 @@
var view = new Uint8Array(data.length);
for (var i = 0; i < data.length; i++) { view[i] = data.charCodeAt(i); }
if ((readState == 0) && (rstr2hex(data) == '4100000000000000')) {
if ((readState == 0) && (rstr2hex(data).startsWith('4100000000000000'))) {
// We are not authenticated, KVM data starts here.
readState = 1;
if (data.length > 8) { amtDesktop.ProcessBinaryData(view.slice(8).buffer); }
} else if (readState == 1) {
amtDesktop.ProcessBinaryData(view.buffer);
}
} else if (recFileProtocol == 200) {
} else if (recFileProtocol == 102) {
// Intel AMT midstream KVM
var view = new Uint8Array(data.length);
for (var i = 0; i < data.length; i++) { view[i] = data.charCodeAt(i); }
@ -600,7 +601,7 @@
}
// This is a PNG screenshot of the display, load it and render it.
if ((type == 3) && (recFileProtocol == 200)) {
if ((type == 3) && (recFileProtocol == 102)) {
var tile = new Image();
tile.src = "data:image/png;base64," + btoa(data);
tile.onload = function () { amtDesktop.canvas.drawImage(tile, 0, 0); }
@ -836,7 +837,7 @@
amtDesktop.onScreenSizeChange = deskAdjust;
amtDesktop.State = 3;
amtDesktop.Start();
if (recFileMetadata.protocol == 200) {
if (recFileMetadata.protocol == 102) {
if (recFileMetadata.screenSize) { amtDesktop.width = recFileMetadata.screenSize[0]; amtDesktop.height = recFileMetadata.screenSize[1]; }
if (recFileMetadata.bpp) { amtDesktop.bpp = recFileMetadata.bpp; }
if (recFileMetadata.graymode) { amtDesktop.graymode = recFileMetadata.graymode; }

View File

@ -4094,7 +4094,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (domain == null) return;
// Check the query
if ((domain.sessionrecording == null) || (req.query.file == null) || (obj.common.IsFilenameValid(req.query.file) !== true) || (req.query.file.endsWith('.mcrec') == false)) { res.sendStatus(401); return; }
if ((domain.sessionrecording == null) || (req.query.file == null) || (obj.common.IsFilenameValid(req.query.file) !== true) || (!req.query.file.endsWith('.mcrec') && !req.query.file.endsWith('.txt'))) { res.sendStatus(401); return; }
// Get the recording path
var recordingsPath = null;
@ -4727,8 +4727,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
// Fetch information about the target
obj.db.Get(req.query.host, function (err, docs) {
if (docs.length == 0) { console.log('ERR: Node not found'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
var node = docs[0];
var xusername = '', xdevicename = '', xdevicename2 = null, node = null;
node = docs[0]; xdevicename2 = node.name; xdevicename = '-' + parent.common.makeFilename(node.name); ws.id = getRandomPassword(); ws.time = Date.now();
if (!node.intelamt) { console.log('ERR: Not AMT node'); try { ws.close(); } catch (e) { } return; } // Disconnect websocket
var ciraconn = parent.mpsserver.GetConnectionToNode(req.query.host, null, false);
// Check if this user has permission to manage this computer
if ((obj.GetNodeRights(user, node.meshid, node._id) & MESHRIGHT_REMOTECONTROL) == 0) { console.log('ERR: Access denied (3)'); try { ws.close(); } catch (e) { } return; }
@ -4782,7 +4784,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (record == true) {
var now = new Date(Date.now());
var recFilename = 'relaysession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + now.getUTCFullYear() + '-' + obj.common.zeroPad(now.getUTCMonth() + 1, 2) + '-' + obj.common.zeroPad(now.getUTCDate(), 2) + '-' + obj.common.zeroPad(now.getUTCHours(), 2) + '-' + obj.common.zeroPad(now.getUTCMinutes(), 2) + '-' + obj.common.zeroPad(now.getUTCSeconds(), 2) + '-' + getRandomPassword() + '.mcrec'
// Get the username and make it acceptable as a filename
if (user._id) { xusername = '-' + parent.common.makeFilename(user._id.split('/')[2]); }
var xsessionid = ws.id;
var recFilename = 'relaysession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + now.getUTCFullYear() + '-' + obj.common.zeroPad(now.getUTCMonth() + 1, 2) + '-' + obj.common.zeroPad(now.getUTCDate(), 2) + '-' + obj.common.zeroPad(now.getUTCHours(), 2) + '-' + obj.common.zeroPad(now.getUTCMinutes(), 2) + '-' + obj.common.zeroPad(now.getUTCSeconds(), 2) + xusername + xdevicename + '-' + xsessionid + '.mcrec';
var recFullFilename = null;
if (domain.sessionrecording.filepath) {
try { obj.fs.mkdirSync(domain.sessionrecording.filepath); } catch (e) { }
@ -4794,16 +4799,32 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
var fd = obj.fs.openSync(recFullFilename, 'w');
if (fd != null) {
// Write the recording file header
var firstBlock = JSON.stringify({ magic: 'MeshCentralRelaySession', ver: 1, userid: user._id, username: user.name, ipaddr: req.clientIp, nodeid: node._id, intelamt: true, protocol: (req.query.p == 2) ? 101 : 100, time: new Date().toLocaleString() })
recordingEntry(fd, 1, 0, firstBlock, function () { });
ws.logfile = { fd: fd, lock: false };
parent.debug('relay', 'Relay: Started recording to file: ' + recFullFilename);
var metadata = {
magic: 'MeshCentralRelaySession',
ver: 1,
userid: user._id,
username: user.name,
sessionid: ws.id,
ipaddr1: req.clientIp,
time: new Date().toLocaleString(),
protocol: (req.query.p == 2) ? 101 : 100,
nodeid: node._id,
intelamt: true
};
if (ciraconn != null) { metadata.ipaddr2 = ciraconn.remoteAddr; }
else if ((conn & 4) != 0) { metadata.ipaddr2 = node.host; }
if (xdevicename2 != null) { metadata.devicename = xdevicename2; }
var firstBlock = JSON.stringify(metadata)
ws.logfile = { fd: fd, lock: false, filename: recFullFilename, startTime: Date.now(), size: 0, text: 0, req: req };
obj.meshRelayHandler.recordingEntry(ws.logfile, 1, 0, firstBlock, function () { });
if (node != null) { ws.logfile.nodeid = node._id; ws.logfile.meshid = node.meshid; ws.logfile.name = node.name; ws.logfile.icon = node.icon; }
if (req.query.p == 2) { ws.send(Buffer.from(String.fromCharCode(0xF0), 'binary')); } // Intel AMT Redirection: Indicate the session is being recorded
}
}
}
// If Intel AMT CIRA connection is available, use it
var ciraconn = parent.mpsserver.GetConnectionToNode(req.query.host, null, false);
if (ciraconn != null) {
parent.debug('web', 'Opening relay CIRA channel connection to ' + req.query.host + '.');
@ -4833,8 +4854,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
if (state == 0) { try { ws.close(); } catch (e) { } }
if (state == 2) {
// TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF
const tlsoptions = { socket: ser, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
if (req.query.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
const tlsoptions = { minVersion: 'TLSv1', socket: ser, ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
// if (req.query.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
var tlsock = obj.tls.connect(tlsoptions, function () { parent.debug('webrelay', "CIRA Secure TLS Connection"); ws._socket.resume(); });
tlsock.chnl = chnl;
tlsock.setEncoding('binary');
@ -4865,7 +4886,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
try { ws.send(data); } catch (e) { }
} else {
// Log to recording file
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } }); // TODO: Add TLS support
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } }); // TODO: Add TLS support
}
}
};
@ -4897,7 +4918,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
try { ws.send(data); } catch (e) { }
} else {
// Log to recording file
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } });
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 0, data, function () { try { ws.send(data); } catch (ex) { console.log(ex); } });
}
}
};
@ -4921,7 +4942,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
try { ws.forwardclient.write(data); } catch (ex) { }
} else {
// Log to recording file
recordingEntry(ws.logfile.fd, 2, 2, data, function () { try { ws.forwardclient.write(data); } catch (ex) { } });
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 2, data, function () { try { ws.forwardclient.write(data); } catch (ex) { } });
}
});
@ -4930,6 +4951,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
console.log('CIRA server websocket error from ' + req.clientIp + ', ' + err.toString().split('\r')[0] + '.');
parent.debug('webrelay', 'Websocket relay closed on error.');
// Log the disconnection
if (ws.time) {
if (req.query.p == 2) { // Only log event if Intel Redirection, otherwise hundreds of logs for WSMAN are recorded
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
if (user) {
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: 101, nodeid: node._id };
obj.parent.DispatchEvent(['*', user._id, node._id, node.meshid], obj, event);
}
}
}
// Websocket closed, close the CIRA channel and TLS session.
if (ws.forwardclient) {
if (ws.forwardclient.close) { ws.forwardclient.close(); } // NonTLS, close the CIRA channel
@ -4939,13 +4971,49 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
}
// Close the recording file
if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); delete ws.logfile; }, ws); }
if (ws.logfile != null) {
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
obj.fs.close(logfile.fd);
parent.debug('relay', 'Relay: Finished recording to file: ' + ws.logfile.filename);
// Compute session length
var sessionLength = null;
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000) - 5; }
// Add a event entry about this recording
var basefile = parent.path.basename(ws.logfile.filename);
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; }
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
var mesh = obj.meshes[ws.logfile.meshid];
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
if (ws.logfile.name) { event.name = ws.logfile.name; }
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
delete ws.logfile;
}, ws);
}, 5000);
}
});
// If the web socket is closed, close the associated TCP connection.
ws.on('close', function (req) {
ws.on('close', function () {
parent.debug('webrelay', 'Websocket relay closed.');
// Log the disconnection
if (ws.time) {
if (req.query.p == 2) { // Only log event if Intel Redirection, otherwise hundreds of logs for WSMAN are recorded
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
var nodeid = node._id;
var meshid = node.meshid;
if (user) {
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: ((req.query.p == 2) ? 101 : 100), nodeid: nodeid };
obj.parent.DispatchEvent(['*', user._id, nodeid, meshid], obj, event);
}
}
}
// Websocket closed, close the CIRA channel and TLS session.
if (ws.forwardclient) {
if (ws.forwardclient.close) { ws.forwardclient.close(); } // NonTLS, close the CIRA channel
@ -4955,7 +5023,30 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
}
// Close the recording file
if (ws.logfile != null) { recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, ws) { obj.fs.close(fd); delete ws.logfile; }, ws); }
if (ws.logfile != null) {
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
obj.fs.close(logfile.fd);
parent.debug('relay', 'Relay: Finished recording to file: ' + ws.logfile.filename);
// Compute session length
var sessionLength = null;
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000) - 5; }
// Add a event entry about this recording
var basefile = parent.path.basename(ws.logfile.filename);
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
if (user) { event.userids = [user._id]; }
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
var mesh = obj.meshes[ws.logfile.meshid];
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
if (ws.logfile.name) { event.name = ws.logfile.name; }
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
delete ws.logfile;
}, ws);
}, 5000);
}
});
// Note that here, req.query.p: 1 = WSMAN with server auth, 2 = REDIR with server auth, 3 = WSMAN without server auth, 4 = REDIR with server auth
@ -4970,12 +5061,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
ws.interceptor = obj.interceptor.CreateRedirInterceptor({ user: node.intelamt.user, pass: node.intelamt.pass });
ws.interceptor.blockAmtStorage = true;
}
return;
}
// If Intel AMT direct connection is possible, option a direct socket
if ((conn & 4) != 0) { // We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
} else if ((conn & 4) != 0) { // If Intel AMT direct connection is possible, option a direct socket
// We got a new web socket connection, initiate a TCP connection to the target Intel AMT host/port.
parent.debug('webrelay', 'Opening relay TCP socket connection to ' + req.query.host + '.');
// When data is received from the web socket, forward the data into the associated TCP connection.
@ -4991,7 +5078,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
try { ws.forwardclient.write(msg); } catch (ex) { }
} else {
// Log to recording file
recordingEntry(ws.logfile.fd, 2, 2, msg, function () { try { ws.forwardclient.write(msg); } catch (ex) { } });
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 2, msg, function () { try { ws.forwardclient.write(msg); } catch (ex) { } });
}
});
@ -4999,28 +5086,80 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
ws.on('error', function (err) {
console.log('Error with relay web socket connection from ' + req.clientIp + ', ' + err.toString().split('\r')[0] + '.');
parent.debug('webrelay', 'Error with relay web socket connection from ' + req.clientIp + '.');
// Log the disconnection
if (ws.time) {
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
if (user) {
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: ((req.query.p == 2) ? 101 : 100), nodeid: node._id };
obj.parent.DispatchEvent(['*', user._id, node._id, node.meshid], obj, event);
}
}
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
// Close the recording file
if (ws.logfile != null) {
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd) {
obj.fs.close(fd);
ws.logfile = null;
});
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
obj.fs.close(logfile.fd);
parent.debug('relay', 'Relay: Finished recording to file: ' + ws.logfile.filename);
// Compute session length
var sessionLength = null;
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000); }
// Add a event entry about this recording
var basefile = parent.path.basename(ws.logfile.filename);
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; }
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
var mesh = obj.meshes[ws.logfile.meshid];
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
if (ws.logfile.name) { event.name = ws.logfile.name; }
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
delete ws.logfile;
}, ws);
}, 5000);
}
});
// If the web socket is closed, close the associated TCP connection.
ws.on('close', function () {
parent.debug('webrelay', 'Closing relay web socket connection to ' + req.query.host + '.');
// Log the disconnection
if (ws.time) {
var msg = 'Ended relay session', msgid = 9, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
if (user) {
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip, Math.floor((Date.now() - ws.time) / 1000)], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: ((req.query.p == 2) ? 101 : 100), nodeid: node._id };
obj.parent.DispatchEvent(['*', user._id, node._id, node.meshid], obj, event);
}
}
if (ws.forwardclient) { try { ws.forwardclient.destroy(); } catch (e) { } }
// Close the recording file
if (ws.logfile != null) {
recordingEntry(ws.logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd) {
obj.fs.close(fd);
ws.logfile = null;
});
setTimeout(function(){ // wait 5 seconds before finishing file for some reason?
obj.meshRelayHandler.recordingEntry(ws.logfile, 3, 0, 'MeshCentralMCREC', function (logfile, ws) {
obj.fs.close(logfile.fd);
parent.debug('relay', 'Relay: Finished recording to file: ' + ws.logfile.filename);
// Compute session length
var sessionLength = null;
if (ws.logfile.startTime != null) { sessionLength = Math.round((Date.now() - ws.logfile.startTime) / 1000); }
// Add a event entry about this recording
var basefile = parent.path.basename(ws.logfile.filename);
var event = { etype: 'relay', action: 'recording', domain: domain.id, nodeid: ws.logfile.nodeid, msg: "Finished recording session" + (sessionLength ? (', ' + sessionLength + ' second(s)') : ''), filename: basefile, size: ws.logfile.size };
if (user) { event.userids = [user._id]; } else if (peer.user) { event.userids = [peer.user._id]; }
var xprotocol = (((ws.logfile.req == null) || (ws.logfile.req.query == null)) ? null : (ws.logfile.req.query.p == 2) ? 101 : 100);
if (xprotocol != null) { event.protocol = parseInt(xprotocol); }
var mesh = obj.meshes[ws.logfile.meshid];
if (mesh != null) { event.meshname = mesh.name; event.meshid = mesh._id; }
if (ws.logfile.startTime) { event.startTime = ws.logfile.startTime; event.lengthTime = sessionLength; }
if (ws.logfile.name) { event.name = ws.logfile.name; }
if (ws.logfile.icon) { event.icon = ws.logfile.icon; }
obj.parent.DispatchEvent(['*', 'recording', ws.logfile.nodeid, ws.logfile.meshid], obj, event);
delete ws.logfile;
}, ws);
}, 5000);
}
});
@ -5038,8 +5177,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
ws._socket.resume();
} else {
// If TLS is going to be used, setup a TLS socket
var tlsoptions = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
if (req.query.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
var tlsoptions = { minVersion: 'TLSv1', ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
// if (req.query.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () {
// The TLS connection method is the same as TCP, but located a bit differently.
parent.debug('webrelay', user.name + ' - TLS connected to ' + node.host + ':' + port + '.');
@ -5064,7 +5203,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
try { ws.send(data); } catch (e) { }
} else {
// Log to recording file
recordingEntry(ws.logfile.fd, 2, 0, data, function () { try { ws.send(data); } catch (e) { } });
obj.meshRelayHandler.recordingEntry(ws.logfile, 2, 0, data, function () { try { ws.send(data); } catch (e) { } });
}
});
@ -5092,9 +5231,32 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
ws._socket.resume();
});
}
return;
}
// Log the connection
if (user != null) {
if (req.query.p == 2) { // Only log event if Intel Redirection, otherwise hundreds of logs for WSMAN are recorded
var msg = 'Started relay session', msgid = 13, ip = ((ciraconn != null) ? ciraconn.remoteAddr : (((conn & 4) != 0) ? node.host : req.clientIp));
var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msgid: msgid, msgArgs: [ws.id, req.clientIp, ip], msg: msg + ' \"' + ws.id + '\" from ' + req.clientIp + ' to ' + ip, protocol: 101, nodeid: node._id };
obj.parent.DispatchEvent(['*', user._id], obj, event);
}
// Update user last access time
if ((user != null)) {
const timeNow = Math.floor(Date.now() / 1000);
if (user.access < (timeNow - 300)) { // Only update user access time if longer than 5 minutes
user.access = timeNow;
obj.parent.db.SetUser(user);
// Event the change
var message = { etype: 'user', userid: user._id, username: user.name, account: obj.CloneSafeUser(user), action: 'accountchange', domain: domain.id, nolog: 1 };
if (parent.db.changeStream) { message.noact = 1; } // If DB change stream is active, don't use this event to change the user. Another event will come.
var targets = ['*', 'server-users', user._id];
if (user.groups) { for (var i in user.groups) { targets.push('server-users:' + i); } }
obj.parent.DispatchEvent(targets, obj, message);
}
}
}
});
}
@ -6557,13 +6719,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
extraFrameSrc = ' https://' + req.headers.host + ':' + parent.webrelayserver.port;
if ((xforwardedhost != null) && (xforwardedhost != req.headers.host)) { extraFrameSrc += ' https://' + xforwardedhost + ':' + parent.webrelayserver.port; }
}
// If using duo add apihostname to CSP
var duoSrc = '';
if ((typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.apihostname == 'string')) {
duoSrc = domain.duo2factor.apihostname;
}
// Finish setup security headers
const headers = {
'Referrer-Policy': 'no-referrer',
'X-XSS-Protection': '1; mode=block',
'X-Content-Type-Options': 'nosniff',
'Content-Security-Policy': "default-src 'none'; font-src 'self' fonts.gstatic.com data:; script-src 'self' 'unsafe-inline' " + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline' fonts.googleapis.com; frame-src 'self' blob: mcrouter:" + extraFrameSrc + "; media-src 'self'; form-action 'self'; manifest-src 'self'"
'Content-Security-Policy': "default-src 'none'; font-src 'self' fonts.gstatic.com data:; script-src 'self' 'unsafe-inline' " + extraScriptSrc + "; connect-src 'self'" + geourl + selfurl + "; img-src 'self' blob: data:" + geourl + " data:; style-src 'self' 'unsafe-inline' fonts.googleapis.com; frame-src 'self' blob: mcrouter:" + extraFrameSrc + "; media-src 'self'; form-action 'self' " + duoSrc + "; manifest-src 'self'"
};
if (req.headers['user-agent'] && (req.headers['user-agent'].indexOf('Chrome') >= 0)) { headers['Permissions-Policy'] = 'interest-cohort=()'; } // Remove Google's FLoC Network, only send this if Chrome browser
if ((parent.config.settings.allowframing !== true) && (typeof parent.config.settings.allowframing !== 'string')) { headers['X-Frame-Options'] = 'sameorigin'; }
@ -9569,7 +9738,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
// Generate a random Intel AMT password
function checkAmtPassword(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
function getRandomAmtPassword() { var p; do { p = Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); } while (checkAmtPassword(p) == false); return p; }
function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').split('/').join('@'); }
function getRandomPassword() { return Buffer.from(obj.crypto.randomBytes(9), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'); }
function getRandomLowerCase(len) { var r = '', random = obj.crypto.randomBytes(len); for (var i = 0; i < len; i++) { r += String.fromCharCode(97 + (random[i] % 26)); } return r; }
// Generate a 8 digit integer with even random probability for each value.
@ -9594,31 +9763,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
}
}
// Record a new entry in a recording log
function recordingEntry(fd, type, flags, data, func, tag) {
try {
if (typeof data == 'string') {
// String write
var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
header.writeInt32BE(blockData.length, 4); // Size
header.writeIntBE(new Date(), 10, 6); // Time
var block = Buffer.concat([header, blockData]);
obj.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
} else {
// Binary write
var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
header.writeInt32BE(data.length, 4); // Size
header.writeIntBE(new Date(), 10, 6); // Time
var block = Buffer.concat([header, data]);
obj.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
}
} catch (ex) { console.log(ex); func(fd, tag); }
}
// Perform a IP match against a list
function isIPMatch(ip, matchList) {
const ipcheck = require('ipcheck');