This commit is contained in:
Ylian Saint-Hilaire 2022-10-20 14:44:47 -07:00
commit a40e40757c
23 changed files with 613 additions and 133 deletions

View File

@ -5,6 +5,7 @@
"accountcreate", "accountcreate",
"accountid", "accountid",
"accountremove", "accountremove",
"acebase",
"acmd", "acmd",
"acmepath", "acmepath",
"actiontype", "actiontype",
@ -599,6 +600,7 @@
"postflight", "postflight",
"poweraction", "poweraction",
"powerevents", "powerevents",
"Preconfigured",
"Proto", "Proto",
"publicid", "publicid",
"pushlogin", "pushlogin",
@ -662,6 +664,7 @@
"rport", "rport",
"rtpass", "rtpass",
"rtuser", "rtuser",
"runas",
"runasuser", "runasuser",
"runasuseronly", "runasuseronly",
"runcommand", "runcommand",
@ -822,6 +825,7 @@
"usercount", "usercount",
"userex", "userex",
"userfiles", "userfiles",
"userfirst",
"usergroupchange", "usergroupchange",
"usergroups", "usergroups",
"userid", "userid",

View File

@ -47,6 +47,32 @@ var MESHRIGHT_NODESKTOP = 65536;
var pendingSetClip = false; // This is a temporary hack to prevent multiple setclips at the same time to stop the agent from crashing. var pendingSetClip = false; // This is a temporary hack to prevent multiple setclips at the same time to stop the agent from crashing.
//
// This is a helper function used by the 32 bit Windows Agent, when running on 64 bit windows. It will check if the agent is already patched for this
// and will use this helper if it is not. This helper will inject 'sysnative' into the results when calling readdirSync() on %windir%.
//
function __readdirSync_fix(path)
{
var sysnative = false;
pathstr = require('fs')._fixwinpath(path);
if (pathstr.split('\\*').join('').toLowerCase() == process.env['windir'].toLowerCase()) { sysnative = true; }
var ret = __readdirSync_old(path);
if (sysnative) { ret.push('sysnative'); }
return (ret);
}
if (process.platform == 'win32' && require('_GenericMarshal').PointerSize == 4 && require('os').arch() == 'x64')
{
if (require('fs').readdirSync.version == null)
{
//
// 32 Bit Windows Agent on 64 bit Windows has not been patched for sysnative issue, so lets use our own solution
//
require('fs').__readdirSync_old = require('fs').readdirSync;
require('fs').readdirSync = __readdirSync_fix;
}
}
function bcdOK() { function bcdOK() {
if (process.platform != 'win32') { return (false); } if (process.platform != 'win32') { return (false); }
if (require('os').arch() == 'x64') { if (require('os').arch() == 'x64') {

View File

@ -103,14 +103,13 @@ if (msh.agentName) { connectArgs.push('--agentName="' + msh.agentName + '"'); }
function _install(parms) function _install(parms)
{ {
var i;
var mstr = require('fs').createWriteStream(process.execPath + '.msh', { flags: 'wb' }); var mstr = require('fs').createWriteStream(process.execPath + '.msh', { flags: 'wb' });
mstr.write('MeshName=' + msh.MeshName + '\n');
mstr.write('MeshType=' + msh.MeshType + '\n'); for (i in msh)
mstr.write('MeshID=' + msh.MeshID + '\n'); {
mstr.write('ServerID=' + msh.ServerID + '\n'); mstr.write(i + '=' + msh[i] + '\n');
mstr.write('MeshServer=' + msh.MeshServer + '\n'); }
if (msh.agentName) { mstr.write('agentName=' + msh.agentName + '\n'); }
if (msh.meshServiceName) { mstr.write('meshServiceName=' + msh.meshServiceName + '\n'); }
mstr.end(); mstr.end();
if (parms == null) { parms = []; } if (parms == null) { parms = []; }
@ -156,7 +155,7 @@ if (process.argv.includes('-translations'))
console.log(JSON.stringify(translation)); console.log(JSON.stringify(translation));
process.exit(); process.exit();
} }
if (process.argv.includes('-help') || (process.platform == 'linux' && process.env['XAUTHORITY']==null && process.env['DISPLAY'] == null)) if (process.argv.includes('-help') || (process.platform == 'linux' && process.env['XAUTHORITY'] == null && process.env['DISPLAY'] == null && process.argv.length == 1))
{ {
console.log("\n" + translation[lang].commands + ": "); console.log("\n" + translation[lang].commands + ": ");
if ((msh.InstallFlags & 1) == 1) if ((msh.InstallFlags & 1) == 1)

View File

@ -269,15 +269,18 @@ function SMBiosTables()
this.amtInfo = function amtInfo(data) { this.amtInfo = function amtInfo(data) {
if (!data) { throw ('no data'); } if (!data) { throw ('no data'); }
var retVal = { AMT: false }; var retVal = { AMT: false };
if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT') { if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT')
{
var amt = data[130].peek(); var amt = data[130].peek();
retVal.AMT = amt[4] ? true : false; retVal.AMT = amt[4] ? true : false;
if (retVal.AMT) { if (retVal.AMT)
{
retVal.enabled = amt[5] ? true : false; retVal.enabled = amt[5] ? true : false;
retVal.storageRedirection = amt[6] ? true : false; retVal.storageRedirection = amt[6] ? true : false;
retVal.serialOverLan = amt[7] ? true : false; retVal.serialOverLan = amt[7] ? true : false;
retVal.kvm = amt[14] ? true : false; retVal.kvm = amt[14] ? true : false;
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro') { if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
{
var settings = data[131].peek(); var settings = data[131].peek();
if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; } if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; }
if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; } if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; }
@ -295,6 +298,14 @@ function SMBiosTables()
} }
} }
} }
if (!retVal.AMT)
{
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
{
var settings = data[131].peek();
if ((settings[20] & 0x08) == 0x08) { retVal.AMT = true; }
}
}
return (retVal); return (retVal);
}; };
this.smTableTypes = { this.smTableTypes = {

View File

@ -269,15 +269,18 @@ function SMBiosTables()
this.amtInfo = function amtInfo(data) { this.amtInfo = function amtInfo(data) {
if (!data) { throw ('no data'); } if (!data) { throw ('no data'); }
var retVal = { AMT: false }; var retVal = { AMT: false };
if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT') { if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT')
{
var amt = data[130].peek(); var amt = data[130].peek();
retVal.AMT = amt[4] ? true : false; retVal.AMT = amt[4] ? true : false;
if (retVal.AMT) { if (retVal.AMT)
{
retVal.enabled = amt[5] ? true : false; retVal.enabled = amt[5] ? true : false;
retVal.storageRedirection = amt[6] ? true : false; retVal.storageRedirection = amt[6] ? true : false;
retVal.serialOverLan = amt[7] ? true : false; retVal.serialOverLan = amt[7] ? true : false;
retVal.kvm = amt[14] ? true : false; retVal.kvm = amt[14] ? true : false;
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro') { if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
{
var settings = data[131].peek(); var settings = data[131].peek();
if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; } if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; }
if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; } if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; }
@ -295,6 +298,14 @@ function SMBiosTables()
} }
} }
} }
if (!retVal.AMT)
{
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
{
var settings = data[131].peek();
if ((settings[20] & 0x08) == 0x08) { retVal.AMT = true; }
}
}
return (retVal); return (retVal);
}; };
this.smTableTypes = { this.smTableTypes = {

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2018 Intel Corporation Copyright 2018-2022 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -89,21 +89,50 @@ function windows_terminal() {
var newCsbi = GM.CreateVariable(22); var newCsbi = GM.CreateVariable(22);
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, newCsbi).Val == 0) { return; } if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, newCsbi).Val == 0) { return; }
if (newCsbi.Deref(4, 2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6, 2).toBuffer().readUInt16LE() != this.currentY) { if (newCsbi.Deref(4, 2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6, 2).toBuffer().readUInt16LE() != this.currentY)
//wchar_t mywbuf[512]; {
//swprintf(mywbuf, 512, TEXT("csbi.dwCursorPosition.X = %d, csbi.dwCursorPosition.Y = %d, newCsbi.dwCursorPosition.X = %d, newCsbi.dwCursorPosition.Y = %d\r\n"), csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, newCsbi.dwCursorPosition.X, newCsbi.dwCursorPosition.Y); //
//OutputDebugString(mywbuf); // Reference for CONSOLE_SCREEN_BUFFER_INFO can be found at:
// https://learn.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
//m_viewOffset = newCsbi.srWindow.Top; //
//WriteMoveCursor((SerialAgent *)this->sa, (char)(newCsbi.dwCursorPosition.Y - m_viewOffset), (char)(newCsbi.dwCursorPosition.X - m_viewOffset));
//LowStackSendData((SerialAgent *)(this->sa), "", 0);
this.currentX = newCsbi.Deref(4, 2).toBuffer().readUInt16LE(); this.currentX = newCsbi.Deref(4, 2).toBuffer().readUInt16LE();
this.currentY = newCsbi.Deref(6, 2).toBuffer().readUInt16LE(); this.currentY = newCsbi.Deref(6, 2).toBuffer().readUInt16LE();
} }
} }
this.ClearScreen = function () { this.ClearScreen = function ()
{
//
// Reference for CONSOLE_SCREEN_BUFFER_INFO can be found at:
// https://learn.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
//
//
// Reference for GetConsoleScreenBufferInfo can be found at:
// https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
//
//
// Reference for FillConsoleOutputCharacter can be found at:
// https://learn.microsoft.com/en-us/windows/console/fillconsoleoutputcharacter
//
//
// Reference for FillConsoleOutputAttribute can be found at:
// https://learn.microsoft.com/en-us/windows/console/fillconsoleoutputattribute
//
//
// Reference for SetConsoleCursorPosition can be found at:
// https://learn.microsoft.com/en-us/windows/console/setconsolecursorposition
//
//
// Reference for SetConsoleWindowInfo can be fount at:
// https://learn.microsoft.com/en-us/windows/console/setconsolewindowinfo
//
var CONSOLE_SCREEN_BUFFER_INFO = GM.CreateVariable(22); var CONSOLE_SCREEN_BUFFER_INFO = GM.CreateVariable(22);
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; } if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
@ -132,6 +161,7 @@ function windows_terminal() {
this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect); this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect);
} }
// This does a rudimentary check if the platform is capable of PowerShell
this.PowerShellCapable = function() this.PowerShellCapable = function()
{ {
if (require('os').arch() == 'x64') if (require('os').arch() == 'x64')
@ -144,6 +174,7 @@ function windows_terminal() {
} }
} }
// Starts a Legacy Windows Terminal Session
this.StartEx = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT, terminalTarget) this.StartEx = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT, terminalTarget)
{ {
// The older windows terminal does not support // The older windows terminal does not support
@ -164,6 +195,8 @@ function windows_terminal() {
this._stdinput = this._kernel32.GetStdHandle(STD_INPUT_HANDLE); this._stdinput = this._kernel32.GetStdHandle(STD_INPUT_HANDLE);
this._stdoutput = this._kernel32.GetStdHandle(STD_OUTPUT_HANDLE); this._stdoutput = this._kernel32.GetStdHandle(STD_OUTPUT_HANDLE);
this._connected = false; this._connected = false;
// Coord structure can be found at: https://learn.microsoft.com/en-us/windows/console/coord-str
var coordScreen = GM.CreateVariable(4); var coordScreen = GM.CreateVariable(4);
coordScreen.Deref(0, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH); coordScreen.Deref(0, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH);
coordScreen.Deref(2, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT); coordScreen.Deref(2, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT);
@ -172,10 +205,21 @@ function windows_terminal() {
rect.Deref(4, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH - 1); rect.Deref(4, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH - 1);
rect.Deref(6, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT - 1); rect.Deref(6, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT - 1);
if (this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0) { //
// Reference for SetConsoleWindowInfo can be found at:
// https://learn.microsoft.com/en-us/windows/console/setconsolewindowinfo
//
if (this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0)
{
throw ('Failed to set Console Screen Size'); throw ('Failed to set Console Screen Size');
} }
if (this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE()).Val == 0) {
//
// Reference for SetConsoleScreenBufferSize can be found at:
// https://learn.microsoft.com/en-us/windows/console/setconsolescreenbuffersize
//
if (this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE()).Val == 0)
{
throw ('Failed to set Console Buffer Size'); throw ('Failed to set Console Buffer Size');
} }
@ -278,8 +322,16 @@ function windows_terminal() {
return (this.stopping); return (this.stopping);
} }
//
// This function uses the SetWinEventHook() method, so we can hook
// All events between EVENT_CONSOLE_CARET and EVENT_CONSOLE_END_APPLICATION
//
this._hookThread = function () this._hookThread = function ()
{ {
//
// Reference for SetWinEventHook() can be found at:
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwineventhook
//
var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; }); var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
ret.userArgs = []; ret.userArgs = [];
for (var a in arguments) for (var a in arguments)
@ -292,24 +344,43 @@ function windows_terminal() {
var p = this._user32.SetWinEventHook.async(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, 0, this._ConsoleWinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); var p = this._user32.SetWinEventHook.async(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, 0, this._ConsoleWinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
p.ready = ret; p.ready = ret;
p.terminal = this; p.terminal = this;
p.then(function (hwinEventHook) { p.then(function (hwinEventHook)
if (hwinEventHook.Val == 0) { {
if (hwinEventHook.Val == 0)
{
this.ready._rej('Error calling SetWinEventHook'); this.ready._rej('Error calling SetWinEventHook');
} else { } else
{
this.terminal.hwinEventHook = hwinEventHook; this.terminal.hwinEventHook = hwinEventHook;
this.ready._res(); this.ready._res();
this.terminal._GetMessage(); this.terminal._GetMessage();
} }
}); });
this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime) { //
// This is the WINEVENTPROC callback for the WinEventHook we set
//
this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime)
{
//
// Reference for WINEVENTPROC can be found at:
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wineventproc
//
if (!this.terminal.hwinEventHook || this.terminal.hwinEventHook.Val != hhook.Val) { return; } if (!this.terminal.hwinEventHook || this.terminal.hwinEventHook.Val != hhook.Val) { return; }
var buffer = null; var buffer = null;
switch (dwEvent.Val) { //
// Reference for Console WinEvents can be found at:
// https://learn.microsoft.com/en-us/windows/console/console-winevents
//
switch (dwEvent.Val)
{
case EVENT_CONSOLE_CARET: case EVENT_CONSOLE_CARET:
// The console caret has moved
break; break;
case EVENT_CONSOLE_UPDATE_REGION: case EVENT_CONSOLE_UPDATE_REGION:
// More than one character has changed
if (!this.terminal.connected) { if (!this.terminal.connected) {
this.terminal.connected = true; this.terminal.connected = true;
this.terminal._stream._promise._res(); this.terminal._stream._promise._res();
@ -321,25 +392,30 @@ function windows_terminal() {
} }
break; break;
case EVENT_CONSOLE_UPDATE_SIMPLE: case EVENT_CONSOLE_UPDATE_SIMPLE:
// A single character has changed
//console.log('UPDATE SIMPLE: [X: ' + LOWORD(idObject.Val) + ' Y: ' + HIWORD(idObject.Val) + ' Char: ' + LOWORD(idChild.Val) + ' Attr: ' + HIWORD(idChild.Val) + ']'); //console.log('UPDATE SIMPLE: [X: ' + LOWORD(idObject.Val) + ' Y: ' + HIWORD(idObject.Val) + ' Char: ' + LOWORD(idChild.Val) + ' Attr: ' + HIWORD(idChild.Val) + ']');
var simplebuffer = { data: [ Buffer.alloc(1, LOWORD(idChild.Val)) ], attributes: [ HIWORD(idChild.Val) ], width: 1, height: 1, x: LOWORD(idObject.Val), y: HIWORD(idObject.Val) }; var simplebuffer = { data: [ Buffer.alloc(1, LOWORD(idChild.Val)) ], attributes: [ HIWORD(idChild.Val) ], width: 1, height: 1, x: LOWORD(idObject.Val), y: HIWORD(idObject.Val) };
this.terminal._SendDataBuffer(simplebuffer); this.terminal._SendDataBuffer(simplebuffer);
break; break;
case EVENT_CONSOLE_UPDATE_SCROLL: case EVENT_CONSOLE_UPDATE_SCROLL:
// The console has scrolled
//console.log('UPDATE SCROLL: [dx: ' + idObject.Val + ' dy: ' + idChild.Val + ']'); //console.log('UPDATE SCROLL: [dx: ' + idObject.Val + ' dy: ' + idChild.Val + ']');
this.terminal._SendScroll(idObject.Val, idChild.Val); this.terminal._SendScroll(idObject.Val, idChild.Val);
break; break;
case EVENT_CONSOLE_LAYOUT: case EVENT_CONSOLE_LAYOUT:
// The console layout has changed.
//console.log('CONSOLE_LAYOUT'); //console.log('CONSOLE_LAYOUT');
//snprintf( Buf, 512, "Event Console LAYOUT!\r\n"); //snprintf( Buf, 512, "Event Console LAYOUT!\r\n");
//SendLayout(); //SendLayout();
break; break;
case EVENT_CONSOLE_START_APPLICATION: case EVENT_CONSOLE_START_APPLICATION:
// A new console process has started
//console.log('START APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']'); //console.log('START APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
//snprintf( Buf, 512, "Event Console START APPLICATION!\r\nProcess ID: %d - Child ID: %d\r\n\r\n", (int)idObject, (int)idChild); //snprintf( Buf, 512, "Event Console START APPLICATION!\r\nProcess ID: %d - Child ID: %d\r\n\r\n", (int)idObject, (int)idChild);
//SendConsoleEvent(dwEvent, idObject, idChild); //SendConsoleEvent(dwEvent, idObject, idChild);
break; break;
case EVENT_CONSOLE_END_APPLICATION: case EVENT_CONSOLE_END_APPLICATION:
// A console process has exited
if (idObject.Val == this.terminal._hProcessID) if (idObject.Val == this.terminal._hProcessID)
{ {
//console.log('END APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']'); //console.log('END APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
@ -360,18 +436,44 @@ function windows_terminal() {
return (ret); return (ret);
} }
this._GetMessage = function () { // Retrieves a message from the calling thread's message queue
this._GetMessage = function ()
{
//
// Reference for GetMessage() can be found at:
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage
//
//
// Reference for TranslateMessage() can be found at:
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-translatemessage
//
//
// Reference for DispatchMessage() can be found at:
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-dispatchmessage
//
if (this._user32.abort) { console.log('aborting loop'); return; } if (this._user32.abort) { console.log('aborting loop'); return; }
this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret) { this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret)
{
//console.log('GetMessage Response'); //console.log('GetMessage Response');
if (ret.Val != 0) { if (ret.Val != 0)
if (ret.Val == -1) { {
if (ret.Val == -1)
{
// handle the error and possibly exit // handle the error and possibly exit
} else { }
else
{
// Translates virtual-key messages into character messages
//console.log('TranslateMessage'); //console.log('TranslateMessage');
this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () { this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
{
// Dispatches a message to a window procedure
//console.log('DispatchMessage'); //console.log('DispatchMessage');
this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () { this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
{
this.nativeProxy.terminal._GetMessage(); this.nativeProxy.terminal._GetMessage();
}, console.log); }, console.log);
}, console.log); }, console.log);
@ -384,7 +486,8 @@ function windows_terminal() {
if (this.nativeProxy.terminal._hProcess == null) { return; } if (this.nativeProxy.terminal._hProcess == null) { return; }
this.nativeProxy.terminal.stopping._res(); this.nativeProxy.terminal.stopping._res();
if (this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0) { if (this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0)
{
var e = this.nativeProxy.terminal._kernel32.GetLastError().Val; var e = this.nativeProxy.terminal._kernel32.GetLastError().Val;
console.log('Unable to kill Terminal Process, error: ' + e); console.log('Unable to kill Terminal Process, error: ' + e);
} }
@ -394,22 +497,38 @@ function windows_terminal() {
console.log('REJECTED_UnhookWinEvent: ' + err); console.log('REJECTED_UnhookWinEvent: ' + err);
}); });
} }
}, function (err) { }, function (err)
{
// Get Message Failed // Get Message Failed
console.log('REJECTED_GETMessage: ' + err); console.log('REJECTED_GETMessage: ' + err);
}); });
} }
this._WriteBuffer = function (buf) {
for (var i = 0; i < buf.length; ++i) { this._WriteBuffer = function (buf)
if (typeof (buf) == 'string') { {
for (var i = 0; i < buf.length; ++i)
{
if (typeof (buf) == 'string')
{
this._WriteCharacter(buf.charCodeAt(i), false); this._WriteCharacter(buf.charCodeAt(i), false);
} else { } else
{
this._WriteCharacter(buf[i], false); this._WriteCharacter(buf[i], false);
} }
} }
} }
this._WriteCharacter = function (key, bControlKey) this._WriteCharacter = function (key, bControlKey)
{ {
//
// Reference for WriteConsoleInput() can be found at:
// https://learn.microsoft.com/en-us/windows/console/writeconsoleinput
//
//
// Reference for INPUT_RECORD can be found at:
// https://learn.microsoft.com/en-us/windows/console/input-record-str
//
var rec = GM.CreateVariable(20); var rec = GM.CreateVariable(20);
rec.Deref(0, 2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType rec.Deref(0, 2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType
rec.Deref(4, 4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown rec.Deref(4, 4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown
@ -427,20 +546,33 @@ function windows_terminal() {
} }
// Get the current visible screen buffer // Get the current visible screen buffer
this._GetScreenBuffer = function (sx, sy, ex, ey) { this._GetScreenBuffer = function (sx, sy, ex, ey)
{
//
// Reference for GetConsoleScreenBufferInfo() can be found at:
// https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
//
//
// Reference for ReadConsoleOutput() can be found at:
// https://learn.microsoft.com/en-us/windows/console/readconsoleoutput
//
var info = GM.CreateVariable(22); var info = GM.CreateVariable(22);
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); } if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); }
var nWidth = info.Deref(14, 2).toBuffer().readUInt16LE() - info.Deref(10, 2).toBuffer().readUInt16LE() + 1; var nWidth = info.Deref(14, 2).toBuffer().readUInt16LE() - info.Deref(10, 2).toBuffer().readUInt16LE() + 1;
var nHeight = info.Deref(16, 2).toBuffer().readUInt16LE() - info.Deref(12, 2).toBuffer().readUInt16LE() + 1; var nHeight = info.Deref(16, 2).toBuffer().readUInt16LE() - info.Deref(12, 2).toBuffer().readUInt16LE() + 1;
if (arguments[3] == null) { if (arguments[3] == null)
{
// Use Default Parameters // Use Default Parameters
sx = 0; sx = 0;
sy = 0; sy = 0;
ex = nWidth - 1; ex = nWidth - 1;
ey = nHeight - 1; ey = nHeight - 1;
} else { } else
{
if (this._scrx != 0) { sx += this._scrx; ex += this._scrx; } if (this._scrx != 0) { sx += this._scrx; ex += this._scrx; }
if (this._scry != 0) { sy += this._scry; ey += this._scry; } if (this._scry != 0) { sy += this._scry; ey += this._scry; }
this._scrx = this._scry = 0; this._scrx = this._scry = 0;
@ -462,7 +594,8 @@ function windows_terminal() {
region.buffer.writeUInt16LE(ex, 4); region.buffer.writeUInt16LE(ex, 4);
region.buffer.writeUInt16LE(ey, 6); region.buffer.writeUInt16LE(ey, 6);
if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0) { if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0)
{
throw ('Unable to read Console Output'); throw ('Unable to read Console Output');
} }
@ -472,12 +605,14 @@ function windows_terminal() {
var retVal = { data: [], attributes: [], width: ex - sx + 1, height: ey - sy + 1, x: sx, y: sy }; var retVal = { data: [], attributes: [], width: ex - sx + 1, height: ey - sy + 1, x: sx, y: sy };
var x, y, line, ifo, tmp, lineWidth = ex - sx + 1; var x, y, line, ifo, tmp, lineWidth = ex - sx + 1;
for (y = 0; y <= (ey - sy) ; ++y) { for (y = 0; y <= (ey - sy) ; ++y)
{
retVal.data.push(Buffer.alloc(lineWidth)); retVal.data.push(Buffer.alloc(lineWidth));
retVal.attributes.push(Buffer.alloc(lineWidth)); retVal.attributes.push(Buffer.alloc(lineWidth));
line = nBuffer.Deref(y * lineWidth * 4, lineWidth * 4).toBuffer(); line = nBuffer.Deref(y * lineWidth * 4, lineWidth * 4).toBuffer();
for (x = 0; x < lineWidth; ++x) { for (x = 0; x < lineWidth; ++x)
{
retVal.data.peek()[x] = line[x * 4]; retVal.data.peek()[x] = line[x * 4];
retVal.attributes.peek()[x] = line[2 + (x * 4)]; retVal.attributes.peek()[x] = line[2 + (x * 4)];
} }
@ -507,6 +642,11 @@ function windows_terminal() {
this._SendScroll = function _SendScroll(dx, dy) this._SendScroll = function _SendScroll(dx, dy)
{ {
//
// Reference for GetConsoleScreenBufferInfo() can be found at:
// https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
//
if (this._scrollTimer || this._stream == null) { return; } if (this._scrollTimer || this._stream == null) { return; }
var info = GM.CreateVariable(22); var info = GM.CreateVariable(22);
@ -546,12 +686,15 @@ function LOWORD(val) { return (val & 0xFFFF); }
function HIWORD(val) { return ((val >> 16) & 0xFFFF); } function HIWORD(val) { return ((val >> 16) & 0xFFFF); }
function GetEsc(op, args) { return (Buffer.from('\x1B[' + args.join(';') + op)); } function GetEsc(op, args) { return (Buffer.from('\x1B[' + args.join(';') + op)); }
function MeshConsole(msg) { require('MeshAgent').SendCommand({ "action": "msg", "type": "console", "value": JSON.stringify(msg) }); } function MeshConsole(msg) { require('MeshAgent').SendCommand({ "action": "msg", "type": "console", "value": JSON.stringify(msg) }); }
function TranslateLine(x, y, data, attributes) { function TranslateLine(x, y, data, attributes)
{
var i, fcolor, bcolor, rcolor, fbright, bbright, lastAttr, fc, bc, rc, fb, bb, esc = [], output = [GetEsc('H', [y, x])]; var i, fcolor, bcolor, rcolor, fbright, bbright, lastAttr, fc, bc, rc, fb, bb, esc = [], output = [GetEsc('H', [y, x])];
if (typeof attributes == 'number') { attributes = [ attributes ]; } // If we get a single attribute, turn it into an array. if (typeof attributes == 'number') { attributes = [attributes]; } // If we get a single attribute, turn it into an array.
for (i = 0; i < data.length; i++) { for (i = 0; i < data.length; i++)
if (lastAttr != attributes[i]) { // To boost performance, if the attribute is the same as the last one, skip this entire part. {
if (lastAttr != attributes[i])
{ // To boost performance, if the attribute is the same as the last one, skip this entire part.
fc = (attributes[i] & 0x0007); fc = (attributes[i] & 0x0007);
fc = ((fc & 0x0001) << 2) + (fc & 0x0002) + ((fc & 0x0004) >> 2); // Foreground color fc = ((fc & 0x0001) << 2) + (fc & 0x0002) + ((fc & 0x0004) >> 2); // Foreground color
bc = (attributes[i] & 0x0070) >> 4; bc = (attributes[i] & 0x0070) >> 4;
@ -564,7 +707,7 @@ function TranslateLine(x, y, data, attributes) {
if (fc != fcolor) { esc.push(fc + 30); fcolor = fc; } // Set the foreground color if needed if (fc != fcolor) { esc.push(fc + 30); fcolor = fc; } // Set the foreground color if needed
if (bc != bcolor) { esc.push(bc + 40); bcolor = bc; } // Set the background color if needed if (bc != bcolor) { esc.push(bc + 40); bcolor = bc; } // Set the background color if needed
if (fb != fbright) { esc.push(2 - fb); fbright = fb; } // Set the bright foreground color if needed if (fb != fbright) { esc.push(2 - fb); fbright = fb; } // Set the bright foreground color if needed
if (bb != bbright) { if (bb == 0) { esc.push(bcolor + 40); } else { esc.push(bcolor + 100); bbright = bb; } } // Set bright Background color if needed if (bb != bbright) { if (bb == 0) { esc.push(bcolor + 40); } else { esc.push(bcolor + 100); bbright = bb; } } // Set bright Background color if needed
if (esc.length > 0) { output.push(GetEsc('m', esc)); esc = []; } if (esc.length > 0) { output.push(GetEsc('m', esc)); esc = []; }
lastAttr = attributes[i]; lastAttr = attributes[i];

View File

@ -47,20 +47,20 @@ function vt()
var GM = require('_GenericMarshal'); var GM = require('_GenericMarshal');
var k32 = GM.CreateNativeProxy('kernel32.dll'); var k32 = GM.CreateNativeProxy('kernel32.dll');
k32.CreateMethod('CancelIoEx'); k32.CreateMethod('CancelIoEx'); // https://learn.microsoft.com/en-us/windows/win32/fileio/cancelioex-func
k32.CreateMethod('CreatePipe'); k32.CreateMethod('CreatePipe'); // https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
k32.CreateMethod('CreateProcessW'); k32.CreateMethod('CreateProcessW'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
k32.CreateMethod('CreatePseudoConsole'); k32.CreateMethod('CreatePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/createpseudoconsole
k32.CreateMethod('CloseHandle'); k32.CreateMethod('CloseHandle'); // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
k32.CreateMethod('ClosePseudoConsole'); k32.CreateMethod('ClosePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/closepseudoconsole
k32.CreateMethod('GetProcessHeap'); k32.CreateMethod('GetProcessHeap'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-getprocessheap
k32.CreateMethod('HeapAlloc'); k32.CreateMethod('HeapAlloc'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc
k32.CreateMethod('InitializeProcThreadAttributeList'); k32.CreateMethod('InitializeProcThreadAttributeList'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist
k32.CreateMethod('ResizePseudoConsole'); k32.CreateMethod('ResizePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/resizepseudoconsole
k32.CreateMethod('UpdateProcThreadAttribute'); k32.CreateMethod('UpdateProcThreadAttribute'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
k32.CreateMethod('WriteFile'); k32.CreateMethod('WriteFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile
k32.CreateMethod('ReadFile'); k32.CreateMethod('ReadFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
k32.CreateMethod('TerminateProcess'); k32.CreateMethod('TerminateProcess'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess
var ret = { _h: GM.CreatePointer(), _consoleInput: GM.CreatePointer(), _consoleOutput: GM.CreatePointer(), _input: GM.CreatePointer(), _output: GM.CreatePointer(), k32: k32 }; var ret = { _h: GM.CreatePointer(), _consoleInput: GM.CreatePointer(), _consoleOutput: GM.CreatePointer(), _input: GM.CreatePointer(), _output: GM.CreatePointer(), k32: k32 };
var attrSize = GM.CreateVariable(8); var attrSize = GM.CreateVariable(8);
@ -77,18 +77,31 @@ function vt()
throw ('Error calling CreatePseudoConsole()'); throw ('Error calling CreatePseudoConsole()');
} }
//
// Reference for STARTUPINFOEXW
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexw
//
//
// Reference for STARTUPINFOW
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow
//
k32.InitializeProcThreadAttributeList(0, 1, 0, attrSize); k32.InitializeProcThreadAttributeList(0, 1, 0, attrSize);
attrList = GM.CreateVariable(attrSize.toBuffer().readUInt32LE()); attrList = GM.CreateVariable(attrSize.toBuffer().readUInt32LE());
var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72); var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72); // Create Structure, 64 bits is 112 bytes, 32 bits is 72 bytes
startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0); startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0); // Write buffer size
attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer()); attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer()); // Write the reference to STARTUPINFOEX
if (k32.InitializeProcThreadAttributeList(attrList, 1, 0, attrSize).Val != 0) if (k32.InitializeProcThreadAttributeList(attrList, 1, 0, attrSize).Val != 0)
{ {
if (k32.UpdateProcThreadAttribute(attrList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, ret._h.Deref(), GM.PointerSize, 0, 0).Val != 0) if (k32.UpdateProcThreadAttribute(attrList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, ret._h.Deref(), GM.PointerSize, 0, 0).Val != 0)
{ {
if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0) if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0) // Create the process to run in the pseudoconsole
{ {
//
// Create a Stream Object, to be able to read/write data to the pseudoconsole
//
ret._startupinfoex = startupinfoex; ret._startupinfoex = startupinfoex;
ret._process = pi.Deref(0); ret._process = pi.Deref(0);
ret._pid = pi.Deref(GM.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE(); ret._pid = pi.Deref(GM.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE();
@ -111,6 +124,10 @@ function vt()
flush(); flush();
} }
}); });
//
// The ProcessInfo object is signaled when the process exits
//
ds._obj = ret; ds._obj = ret;
ret._waiter = require('DescriptorEvents').addDescriptor(pi.Deref(0)); ret._waiter = require('DescriptorEvents').addDescriptor(pi.Deref(0));
ret._waiter.ds = ds; ret._waiter.ds = ds;
@ -151,6 +168,7 @@ function vt()
ds._rpbufRead = GM.CreateVariable(4); ds._rpbufRead = GM.CreateVariable(4);
ds.__read = function __read() ds.__read = function __read()
{ {
// Asyncronously read data from the pseudoconsole
this._rp = this.terminal.k32.ReadFile.async(this.terminal._output.Deref(), this._rpbuf, this._rpbuf._size, this._rpbufRead, 0); this._rp = this.terminal.k32.ReadFile.async(this.terminal._output.Deref(), this._rpbuf, this._rpbuf._size, this._rpbufRead, 0);
this._rp.then(function () this._rp.then(function ()
{ {
@ -173,6 +191,8 @@ function vt()
} }
throw ('Internal Error'); throw ('Internal Error');
} }
// This evaluates whether or not the powershell binary exists
this.PowerShellCapable = function () this.PowerShellCapable = function ()
{ {
if (require('os').arch() == 'x64') if (require('os').arch() == 'x64')
@ -184,10 +204,14 @@ function vt()
return (require('fs').existsSync(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe')); return (require('fs').existsSync(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'));
} }
} }
// Start the PseudoConsole with the Command Prompt
this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT) this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
{ {
return (this.Create(process.env['windir'] + '\\System32\\cmd.exe', CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)); return (this.Create(process.env['windir'] + '\\System32\\cmd.exe', CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT));
} }
// Start the PseduoConsole with PowerShell
this.StartPowerShell = function StartPowerShell(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT) this.StartPowerShell = function StartPowerShell(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
{ {
if (require('os').arch() == 'x64') if (require('os').arch() == 'x64')

View File

@ -282,7 +282,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
// Construct the HTTP request // Construct the HTTP request
var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n'; var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n';
const blockedHeaders = ['origin', 'cookie', 'upgrade-insecure-requests', 'sec-ch-ua', 'sec-ch-ua-mobile', 'dnt', 'sec-fetch-user', 'sec-ch-ua-platform', 'sec-fetch-site', 'sec-fetch-mode', 'sec-fetch-dest']; // These are headers we do not forward const blockedHeaders = ['cookie', 'upgrade-insecure-requests', 'sec-ch-ua', 'sec-ch-ua-mobile', 'dnt', 'sec-fetch-user', 'sec-ch-ua-platform', 'sec-fetch-site', 'sec-fetch-mode', 'sec-fetch-dest']; // These are headers we do not forward
for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } } for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } }
var cookieStr = ''; var cookieStr = '';
for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); } for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); }
@ -331,7 +331,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
// Construct the HTTP request // Construct the HTTP request
var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n'; var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n';
const blockedHeaders = ['origin', 'cookie', 'sec-websocket-extensions']; // These are headers we do not forward const blockedHeaders = ['cookie', 'sec-websocket-extensions']; // These are headers we do not forward
for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } } for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } }
var cookieStr = ''; var cookieStr = '';
for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); } for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); }

View File

@ -1,27 +0,0 @@
# FAQ
## Help! I've been hacked there are weird agents appearing in my Tactical RMM
No, you haven't.
1. Your agent installer was scanned by an antivirus.
2. It didn't recognize the exe.
3. You have the option enabled to submit unknown applications for analysis.
![AV Option1](images/faq_av_option1.png)
4. They ran it against their virtualization testing cluster.
5. You allow anyone to connect to your rmm server (you should look into techniques to hide your server from the internet).
6. Here are some examples of what that looks like.
# Can't login on server after first setup
You're sure you're typing in everything right, giving it 2FA code and can't login
[TOTP](https://en.wikipedia.org/wiki/Time-based_one-time_password) is time sensitive, check your time/NTP and make sure it's right (on server and TOTP app device)! :)
![](images/2022-08-04-18-19-19.png)

View File

@ -9,7 +9,7 @@ npm install meshcentral
node node_modules/meshcentral node node_modules/meshcentral
``` ```
That's it. MeshCentral will set itself up and start managing computers on your local network. By default it will be setup in LAN mode and agents you install will multicast on the local network to find the server. To setup the server so that agents use a well known DNS name and to start customizing your server, go in the "meshcentral-data" folder and edit the config.json file. The configuration file must be valid JSON, you can use this link to validate the file format. That's it. MeshCentral will set itself up and start managing computers on your local network. By default it will be setup in LAN mode and agents you install will multicast on the local network to find the server. To setup the server so that agents use a well known DNS name and to start customizing your server, go in the "meshcentral-data" folder and edit the config.json file. The configuration file must be valid JSON, you can use this [link](https://duckduckgo.com/?va=j&t=hc&q=json+lint&ia=answer) to validate the file format.
For Windows users, you can download the MeshCentral Installer that will automate installation of NodeJS and provide basic configuration of the server. This option is not recommended for advanced users. For Windows users, you can download the MeshCentral Installer that will automate installation of NodeJS and provide basic configuration of the server. This option is not recommended for advanced users.

View File

@ -0,0 +1,37 @@
# SSL/Letsencrypt
## MeshCentral supports SSL using self generated certs, your own certs or Letsencrypt
### Enabling letsencrypt
Make sure you match and/or adjust all the following settings appropriately in your config.json file:
```json
{
"settings": {
"redirPort"
"cert": "yourdomain.com"
},
"domains": {
"letsencrypt": {
"__comment__": "Requires NodeJS 8.x or better, Go to https://letsdebug.net/ first before trying Let's Encrypt.",
"email": "myemail@myserver.com",
"names": "myserver.com,customer1.myserver.com",
"skipChallengeVerification": false,
"production": true
},
}
}
```
If you need further clarification to know what each of these settings are, check out [the config schema](https://github.com/Ylianst/MeshCentral/blob/master/meshcentral-config-schema.json).
Then restart meshcentral and it will get a cert for you, the process will need to restart to apply the cert.
### Useful resources/troubleshooting
To check letsencrypt is working properly please use https://letsdebug.net/. We are using the [HTTP-O1 challenge](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) method with these instructions.
Also make sure you have port 80 open and pointing to your meshcentral server, **IT WILL NOT WORK** if port 80 isn't open and it **HAS** to be port 80.
You can read more about Letsencrypt and meshcentral [here](https://ylianst.github.io/MeshCentral/meshcentral/#lets-encrypt-support).

View File

@ -25,6 +25,8 @@ xxx Path: `c:\Program Files\Mesh Agent\meshagent.msh`
## Linux / BSD ## Linux / BSD
Uninstall: `sudo /usr/local/mesh_services/meshagent/[agent-name]/meshagent -fulluninstall`
## Apple macOS Binary Installer ## Apple macOS Binary Installer
Default Install Path: `/usr/local/mesh_services/meshagent/meshagent` Default Install Path: `/usr/local/mesh_services/meshagent/meshagent`
@ -38,6 +40,10 @@ launchctl stop meshagent
launchctl start meshagent launchctl start meshagent
``` ```
Install:
Uninstall: `sudo /usr/local/mesh_services/meshagent/[agent-name]/meshagent -fulluninstall`
## Apple macOS Universal ## Apple macOS Universal
For OSx 11+ including Big Sur, Monterey and later For OSx 11+ including Big Sur, Monterey and later

View File

@ -356,7 +356,7 @@ See description for information about each item.
"loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." }, "loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." },
"agentKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that agents add the value ?key=xxx in the URL in order to connect. This is not automatic and needs to be manually added in the meshagent.msh file." }, "agentKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that agents add the value ?key=xxx in the URL in order to connect. This is not automatic and needs to be manually added in the meshagent.msh file." },
"ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." }, "ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." },
"minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sided web pages." }, "minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sized web pages." },
"newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." }, "newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." },
"newAccountsPass": { "type": "string", "default": null, "description": "When set this password will be required in order to create a new account from the login screen." }, "newAccountsPass": { "type": "string", "default": null, "description": "When set this password will be required in order to create a new account from the login screen." },
"newAccountsCaptcha": { "type": "boolean", "default": false, "description": "When set to true, users will get a CAPTCHA when creating a new account from the login screen." }, "newAccountsCaptcha": { "type": "boolean", "default": false, "description": "When set to true, users will get a CAPTCHA when creating a new account from the login screen." },
@ -410,12 +410,12 @@ See description for information about each item.
"enum": [ "bat", "ps1", "sh", "agent" ] "enum": [ "bat", "ps1", "sh", "agent" ]
}, },
"runas": { "runas": {
"description": "How to run this script, does not appy to agent scripts.", "description": "How to run this script, does not apply to agent scripts.",
"type": "string", "type": "string",
"enum": ["agent", "userfirst", "user"] "enum": ["agent", "userfirst", "user"]
}, },
"cmd": { "cmd": {
"description": "The command or \\r\\n seperated commands to run, if set do not use the file key.", "description": "The command or \\r\\n separated commands to run, if set do not use the file key.",
"type": "string" "type": "string"
}, },
"file": { "file": {
@ -562,13 +562,13 @@ See description for information about each item.
"ldapSyncWithUserGroups": { "ldapSyncWithUserGroups": {
"type": [ "boolean", "object" ], "type": [ "boolean", "object" ],
"default": false, "default": false,
"description": "When set to true or set to an object, MeshCentral will syncronized LDAP user memberships to MeshCentral user groups.", "description": "When set to true or set to an object, MeshCentral will synchronize LDAP user memberships to MeshCentral user groups.",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"filter": { "filter": {
"type": [ "string", "array" ], "type": [ "string", "array" ],
"default": null, "default": null,
"description": "When set to a string or array of strings, only LDAP membership groups that includes one of the strings will be syncronized with MeshCentral user groups." "description": "When set to a string or array of strings, only LDAP membership groups that includes one of the strings will be synchronized with MeshCentral user groups."
} }
} }
}, },

View File

@ -0,0 +1,50 @@
# FAQ
## json config files
Any item in the config.json file starting with an underscore character are ignored.
Ignored
```json
"_title": "MyServer"
```
Valid setting
```json
"title": "MyServer"
```
json requires correct formatting, if in doubt copy/paste your json config into a web based format checker to make sure you have it right: <https://duckduckgo.com/?va=j&t=hc&q=json+lint&ia=answer>
## Help! I've been hacked there are weird agents appearing in my MeshCentral Console
No, you haven't.
1. Your agent installer was scanned by an antivirus.
2. It didn't recognize the exe.
3. You have the option enabled to submit unknown applications for analysis.
![AV Option1](images/faq_av_option1.png)
4. They ran it against their virtualization testing cluster.
5. You allow anyone to connect to your server (you should look into techniques to hide your server from the internet).
6. Here are some examples of what that looks like.
# Can't login on server after first setup
You're sure you're typing in everything right, giving it 2FA code and can't login
[TOTP](https://en.wikipedia.org/wiki/Time-based_one-time_password) is time sensitive, check your time/NTP and make sure it's right (on server and TOTP app device)! :)
![](images/2022-08-04-18-19-19.png)
# Branding and Customisation
You can brand and customise MeshCentral almost as much as you like without delving into the code, a few changes in the config.json file and uplaoding images can change the way your system looks. Read more [here](https://ylianst.github.io/MeshCentral/meshcentral/#branding-terms-of-use)

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -1201,7 +1201,11 @@ And taking authentication to the next step is removing the login page entirely.
## Branding & Terms of use ## Branding & Terms of use
Once MeshCentral is setup, you may want to customize the web site with your own brand and terms of use. This is important to personalize the web site to your organization. We also want to customize the web site in such a way that updating to the latest version will keep the branding as-is. Whitelabeling your MeshCentral installation to personalize it to your companies brand, as well as having your own terms of use is one of the first things many people do after installation.
<div class="video-wrapper">
<iframe width="320" height="180" src="https://www.youtube.com/embed/xUZ1w9RSKpQ" frameborder="0" allowfullscreen></iframe>
</div>
### Branding ### Branding
@ -1209,7 +1213,7 @@ You can put you own logo on the top of the web page. To get started, get the fil
![](images/2022-05-19-00-38-51.png) ![](images/2022-05-19-00-38-51.png)
Once done, edit the config.json file and set the following values: Once done, edit the config.json file and set one or all of the following values:
```json ```json
"domains": { "domains": {
@ -1217,6 +1221,16 @@ Once done, edit the config.json file and set the following values:
"Title": "", "Title": "",
"Title2": "", "Title2": "",
"TitlePicture": "title-sample.png", "TitlePicture": "title-sample.png",
"loginPicture": "logintitle-sample.png",
"welcomeText": "This is sample text",
"welcomePicture": "mainwelcome-04.jpg",
"welcomePictureFullScreen": true,
"siteStyle": "1",
"nightMode": "1",
"meshMessengerTitle": "Mesh Chat",
"meshMessengerPicture": "chatimage.png",
"footer": "This is a HTML string displayed at the bottom of the web page when a user is logged in.",
"loginfooter": "This is a HTML string displayed at the bottom of the web page when a user is not logged in."
}, },
``` ```
@ -1240,6 +1254,8 @@ This is great to personalize the look of the server within the web site.
### Agent Branding ### Agent Branding
You can also customize the Agent to add your own logo.
![](images/2022-08-24-06-42-40.png) ![](images/2022-08-24-06-42-40.png)
### Terms of use ### Terms of use

View File

@ -1,3 +1,8 @@
/* Maximum space for text block */
.md-grid {
max-width: 95%; /* or 100%, if you want to stretch to full-width */
}
.md-header { .md-header {
background-color: #0b3e81 !important; background-color: #0b3e81 !important;
color: white !important; color: white !important;

View File

@ -15,8 +15,11 @@ nav:
- 'Debugging': 'meshcentral/debugging.md' - 'Debugging': 'meshcentral/debugging.md'
- 'Device Tabs': 'meshcentral/devicetabs.md' - 'Device Tabs': 'meshcentral/devicetabs.md'
- 'Plugins': 'meshcentral/plugins.md' - 'Plugins': 'meshcentral/plugins.md'
- 'SSL': 'meshcentral/SSLnletsencrypt.md'
- 'Security': 'meshcentral/security.md' - 'Security': 'meshcentral/security.md'
- 'Tokens': 'meshcentral/tokens.md' - 'Tokens': 'meshcentral/tokens.md'
- 'FAQ': 'meshcentral/faq.md'
- 'Tips n Tricks': 'meshcentral/tipsntricks.md'
- Design and Architecture: - Design and Architecture:
- design/index.md - design/index.md

View File

@ -349,7 +349,7 @@
"loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." }, "loginKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that users add the value ?key=xxx in the URL in order to see the web site." },
"agentKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that agents add the value ?key=xxx in the URL in order to connect. This is not automatic and needs to be manually added in the meshagent.msh file." }, "agentKey": { "type": [ "string", "array" ], "items": { "type": "string" }, "default": null, "description": "Requires that agents add the value ?key=xxx in the URL in order to connect. This is not automatic and needs to be manually added in the meshagent.msh file." },
"ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." }, "ipkvm": { "type": "boolean", "default": false, "description": "Set to true to enable IP KVM device support in this domain." },
"minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sided web pages." }, "minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sized web pages." },
"newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." }, "newAccounts": { "type": "boolean", "default": false, "description": "When set to true, allow new user accounts to be created from the login page." },
"newAccountsPass": { "type": "string", "default": null, "description": "When set this password will be required in order to create a new account from the login screen." }, "newAccountsPass": { "type": "string", "default": null, "description": "When set this password will be required in order to create a new account from the login screen." },
"newAccountsCaptcha": { "type": "boolean", "default": false, "description": "When set to true, users will get a CAPTCHA when creating a new account from the login screen." }, "newAccountsCaptcha": { "type": "boolean", "default": false, "description": "When set to true, users will get a CAPTCHA when creating a new account from the login screen." },
@ -403,12 +403,12 @@
"enum": [ "bat", "ps1", "sh", "agent" ] "enum": [ "bat", "ps1", "sh", "agent" ]
}, },
"runas": { "runas": {
"description": "How to run this script, does not appy to agent scripts.", "description": "How to run this script, does not apply to agent scripts.",
"type": "string", "type": "string",
"enum": ["agent", "userfirst", "user"] "enum": ["agent", "userfirst", "user"]
}, },
"cmd": { "cmd": {
"description": "The command or \\r\\n seperated commands to run, if set do not use the file key.", "description": "The command or \\r\\n separated commands to run, if set do not use the file key.",
"type": "string" "type": "string"
}, },
"file": { "file": {
@ -555,13 +555,13 @@
"ldapSyncWithUserGroups": { "ldapSyncWithUserGroups": {
"type": [ "boolean", "object" ], "type": [ "boolean", "object" ],
"default": false, "default": false,
"description": "When set to true or set to an object, MeshCentral will syncronized LDAP user memberships to MeshCentral user groups.", "description": "When set to true or set to an object, MeshCentral will synchronize LDAP user memberships to MeshCentral user groups.",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"filter": { "filter": {
"type": [ "string", "array" ], "type": [ "string", "array" ],
"default": null, "default": null,
"description": "When set to a string or array of strings, only LDAP membership groups that includes one of the strings will be syncronized with MeshCentral user groups." "description": "When set to a string or array of strings, only LDAP membership groups that includes one of the strings will be synchronized with MeshCentral user groups."
} }
} }
}, },

View File

@ -1420,7 +1420,7 @@ function CreateMeshCentralServer(config, args) {
if (obj.args.mpsaliasport != null && (typeof obj.args.mpsaliasport != 'number')) obj.args.mpsaliasport = null; if (obj.args.mpsaliasport != null && (typeof obj.args.mpsaliasport != 'number')) obj.args.mpsaliasport = null;
if (obj.args.rediraliasport != null && (typeof obj.args.rediraliasport != 'number')) obj.args.rediraliasport = null; if (obj.args.rediraliasport != null && (typeof obj.args.rediraliasport != 'number')) obj.args.rediraliasport = null;
if (obj.args.redirport == null) obj.args.redirport = 80; if (obj.args.redirport == null) obj.args.redirport = 80;
if (obj.args.minifycore === 0) obj.args.minifycore = false; if (obj.args.minifycore == null) obj.args.minifycore = false;
if (typeof args.agentidletimeout != 'number') { args.agentidletimeout = 150000; } else { args.agentidletimeout *= 1000 } // Default agent idle timeout is 2m, 30sec. if (typeof args.agentidletimeout != 'number') { args.agentidletimeout = 150000; } else { args.agentidletimeout *= 1000 } // Default agent idle timeout is 2m, 30sec.
if ((obj.args.lanonly != true) && (obj.args.webrtconfig == null)) { obj.args.webrtconfig = { iceservers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun.services.mozilla.com' }] }; } // Setup default WebRTC STUN servers if ((obj.args.lanonly != true) && (obj.args.webrtconfig == null)) { obj.args.webrtconfig = { iceservers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun.services.mozilla.com' }] }; } // Setup default WebRTC STUN servers
if (typeof obj.args.ignoreagenthashcheck == 'string') { if (obj.args.ignoreagenthashcheck == '') { delete obj.args.ignoreagenthashcheck; } else { obj.args.ignoreagenthashcheck = obj.args.ignoreagenthashcheck.split(','); } } if (typeof obj.args.ignoreagenthashcheck == 'string') { if (obj.args.ignoreagenthashcheck == '') { delete obj.args.ignoreagenthashcheck; } else { obj.args.ignoreagenthashcheck = obj.args.ignoreagenthashcheck.split(','); } }

View File

@ -579,6 +579,7 @@ if (args['_'].length == 0) {
console.log("\r\nOptional arguments:\r\n"); console.log("\r\nOptional arguments:\r\n");
console.log(" --desc [description] - New group description."); console.log(" --desc [description] - New group description.");
console.log(" --amtonly - New group is agent-less, Intel AMT only."); console.log(" --amtonly - New group is agent-less, Intel AMT only.");
console.log(" --agentless - New group is agent-less only.");
console.log(" --features [number] - Set device group features, sum of numbers below."); console.log(" --features [number] - Set device group features, sum of numbers below.");
console.log(" 1 = Auto-Remove 2 = Hostname Sync"); console.log(" 1 = Auto-Remove 2 = Hostname Sync");
console.log(" 4 = Record Sessions"); console.log(" 4 = Record Sessions");
@ -1356,6 +1357,7 @@ function serverConnect() {
var op = { action: 'createmesh', meshname: args.name, meshtype: 2, responseid: 'meshctrl' }; var op = { action: 'createmesh', meshname: args.name, meshtype: 2, responseid: 'meshctrl' };
if (args.desc) { op.desc = args.desc; } if (args.desc) { op.desc = args.desc; }
if (args.amtonly) { op.meshtype = 1; } if (args.amtonly) { op.meshtype = 1; }
if (args.agentless) { op.meshtype = 3; }
if (args.features) { op.flags = parseInt(args.features); } if (args.features) { op.flags = parseInt(args.features); }
if (args.consent) { op.consent = parseInt(args.consent); } if (args.consent) { op.consent = parseInt(args.consent); }
ws.send(JSON.stringify(op)); ws.send(JSON.stringify(op));

View File

@ -494,6 +494,8 @@
{ {
"bs": "“ zatražio pomoć.", "bs": "“ zatražio pomoć.",
"en": "\" requested help.", "en": "\" requested help.",
"nl": "\" vraagt om hulp.",
"pl": "\" prosi o pomoc.",
"xloc": [ "xloc": [
"device-help.html->2->3" "device-help.html->2->3"
] ]
@ -5939,6 +5941,7 @@
"bs": "Zapisi tokena za prijavu na račun", "bs": "Zapisi tokena za prijavu na račun",
"en": "Account login token records", "en": "Account login token records",
"nl": "Token vermeldingen voor accountaanmelding", "nl": "Token vermeldingen voor accountaanmelding",
"pl": "Zapisy logowania tokenami użytkownika",
"xloc": [ "xloc": [
"default.handlebars->47->2918" "default.handlebars->47->2918"
] ]
@ -9639,6 +9642,7 @@
"bs": "Došlo je do nepoznate greške.", "bs": "Došlo je do nepoznate greške.",
"en": "An unknown error occured.", "en": "An unknown error occured.",
"nl": "Er is een onbekende fout opgetreden.", "nl": "Er is een onbekende fout opgetreden.",
"pl": "Wystąpił nieznany błąd.",
"xloc": [ "xloc": [
"default.handlebars->47->2798" "default.handlebars->47->2798"
] ]
@ -15761,6 +15765,7 @@
"bs": "Naredbe iz datoteke", "bs": "Naredbe iz datoteke",
"en": "Commands from file", "en": "Commands from file",
"nl": "Opdrachten uit bestand", "nl": "Opdrachten uit bestand",
"pl": "Komendy z pliku",
"xloc": [ "xloc": [
"default.handlebars->47->730" "default.handlebars->47->730"
] ]
@ -15769,6 +15774,7 @@
"bs": "Komande iz datoteke na serveru", "bs": "Komande iz datoteke na serveru",
"en": "Commands from file on server", "en": "Commands from file on server",
"nl": "Opdrachten uit een bestand op de server", "nl": "Opdrachten uit een bestand op de server",
"pl": "Komendy z pliku na serwerze",
"xloc": [ "xloc": [
"default.handlebars->47->731" "default.handlebars->47->731"
] ]
@ -15777,6 +15783,7 @@
"bs": "Naredbe iz okvira za tekst", "bs": "Naredbe iz okvira za tekst",
"en": "Commands from text box", "en": "Commands from text box",
"nl": "Opdrachten uit tekstvak", "nl": "Opdrachten uit tekstvak",
"pl": "Komendy z okienka tekstowego",
"xloc": [ "xloc": [
"default.handlebars->47->729" "default.handlebars->47->729"
] ]
@ -15939,6 +15946,7 @@
"bs": "Zapisi konfiguracionih datoteka", "bs": "Zapisi konfiguracionih datoteka",
"en": "Configuration file records", "en": "Configuration file records",
"nl": "Configuratiebestand vermeldingen", "nl": "Configuratiebestand vermeldingen",
"pl": "Zapisy pliku konfiguracyjnego",
"xloc": [ "xloc": [
"default.handlebars->47->2911" "default.handlebars->47->2911"
] ]
@ -19523,6 +19531,7 @@
"bs": "Zapisi baze podataka", "bs": "Zapisi baze podataka",
"en": "Database Records", "en": "Database Records",
"nl": "Database vermeldingen", "nl": "Database vermeldingen",
"pl": "Zapisy Bazy Danych",
"xloc": [ "xloc": [
"default.handlebars->47->2837" "default.handlebars->47->2837"
] ]
@ -20402,6 +20411,8 @@
{ {
"bs": "Odbijena prijava korisnika sa {0}, {1}, {2}", "bs": "Odbijena prijava korisnika sa {0}, {1}, {2}",
"en": "Denied user login from {0}, {1}, {2}", "en": "Denied user login from {0}, {1}, {2}",
"nl": "Geweigerde gebruikerslogin van {0}, {1}, {2}",
"pl": "Odmówiono zalogowania użytkownika z {0}, {1}, {2}",
"xloc": [ "xloc": [
"default.handlebars->47->2406" "default.handlebars->47->2406"
] ]
@ -21210,6 +21221,8 @@
{ {
"bs": "uređaj \"", "bs": "uređaj \"",
"en": "Device \"", "en": "Device \"",
"nl": "Apparaat \"",
"pl": "Urządzenie \"",
"xloc": [ "xloc": [
"device-help.html->2->3" "device-help.html->2->3"
] ]
@ -21217,6 +21230,8 @@
{ {
"bs": "Uređaj \"[[[DEVICENAME]]]\" je zatražio pomoć.", "bs": "Uređaj \"[[[DEVICENAME]]]\" je zatražio pomoć.",
"en": "Device \"[[[DEVICENAME]]]\" requested assistance.", "en": "Device \"[[[DEVICENAME]]]\" requested assistance.",
"nl": "Apparaat \"[[[DEVICENAME]]]\" heeft assistentie gevraagd",
"pl": "Urządzenie \"[[[DEVICENAME]]]\" prosiło o pomoc.",
"xloc": [ "xloc": [
"device-help.txt" "device-help.txt"
] ]
@ -21643,6 +21658,7 @@
"bs": "Zapis push obavijesti uređaja", "bs": "Zapis push obavijesti uređaja",
"en": "Device Push Notification Record", "en": "Device Push Notification Record",
"nl": "Apparaat Push Notificatie vermelding", "nl": "Apparaat Push Notificatie vermelding",
"pl": "Zapis Powiadomień Push Urządzenia",
"xloc": [ "xloc": [
"default.handlebars->47->2920" "default.handlebars->47->2920"
] ]
@ -21651,6 +21667,7 @@
"bs": "SMBIOS zapis uređaja", "bs": "SMBIOS zapis uređaja",
"en": "Device SMBIOS record", "en": "Device SMBIOS record",
"nl": "Apparaat SMBIOS vermelding", "nl": "Apparaat SMBIOS vermelding",
"pl": "Zapis SMBIOS urządzenia",
"xloc": [ "xloc": [
"default.handlebars->47->2919" "default.handlebars->47->2919"
] ]
@ -22029,6 +22046,7 @@
"bs": "Zapis grupe uređaja", "bs": "Zapis grupe uređaja",
"en": "Device group record", "en": "Device group record",
"nl": "Apparaatgroep vermelding", "nl": "Apparaatgroep vermelding",
"pl": "Zapis grupy urządzeń",
"xloc": [ "xloc": [
"default.handlebars->47->2905" "default.handlebars->47->2905"
] ]
@ -22115,6 +22133,7 @@
"bs": "Zapisi informacija o uređaju", "bs": "Zapisi informacija o uređaju",
"en": "Device information records", "en": "Device information records",
"nl": "Apparaatinformatie vermeldingen", "nl": "Apparaatinformatie vermeldingen",
"pl": "Zapisy informacji urządzenia",
"xloc": [ "xloc": [
"default.handlebars->47->2907" "default.handlebars->47->2907"
] ]
@ -22657,6 +22676,7 @@
"bs": "Zapisi o prelasku napajanja uređaja", "bs": "Zapisi o prelasku napajanja uređaja",
"en": "Device power transition records", "en": "Device power transition records",
"nl": "Apparaat aan/uit vermeldingen", "nl": "Apparaat aan/uit vermeldingen",
"pl": "Zapisy zmiany stanu zasilania",
"xloc": [ "xloc": [
"default.handlebars->47->2913" "default.handlebars->47->2913"
] ]
@ -22665,6 +22685,7 @@
"bs": "Zapis uređaja", "bs": "Zapis uređaja",
"en": "Device record", "en": "Device record",
"nl": "Apparaat vermelding", "nl": "Apparaat vermelding",
"pl": "Zapis urządzenia",
"xloc": [ "xloc": [
"default.handlebars->47->2904" "default.handlebars->47->2904"
] ]
@ -22725,6 +22746,7 @@
"bs": "Zapisi o dijeljenju uređaja", "bs": "Zapisi o dijeljenju uređaja",
"en": "Device sharing records", "en": "Device sharing records",
"nl": "Apparaten delings vermeldingen", "nl": "Apparaten delings vermeldingen",
"pl": "Zapisy udostępniania urządzenia",
"xloc": [ "xloc": [
"default.handlebars->47->2917" "default.handlebars->47->2917"
] ]
@ -22733,6 +22755,7 @@
"bs": "Uređaj, korisnici, grupe i drugi zapisi", "bs": "Uređaj, korisnici, grupe i drugi zapisi",
"en": "Device, users, groups and other records", "en": "Device, users, groups and other records",
"nl": "Apparaat, gebruikers, groepen en andere vermeldingen", "nl": "Apparaat, gebruikers, groepen en andere vermeldingen",
"pl": "Zapisy urządzenia, użytkowników, grup i inne",
"xloc": [ "xloc": [
"default.handlebars->47->2921" "default.handlebars->47->2921"
] ]
@ -25980,6 +26003,8 @@
{ {
"bs": "Pošaljite zahtjev za pomoć e-poštom", "bs": "Pošaljite zahtjev za pomoć e-poštom",
"en": "Email Help Request", "en": "Email Help Request",
"nl": "E-mail hulpverzoek",
"pl": "Prośba Pomocy Email",
"xloc": [ "xloc": [
"default.handlebars->47->1939", "default.handlebars->47->1939",
"default.handlebars->47->889" "default.handlebars->47->889"
@ -28036,6 +28061,7 @@
"bs": "Evidencija događaja", "bs": "Evidencija događaja",
"en": "Event records", "en": "Event records",
"nl": "Gebeurtenis vermeldingen", "nl": "Gebeurtenis vermeldingen",
"pl": "Zapisy zdarzeń",
"xloc": [ "xloc": [
"default.handlebars->47->2914" "default.handlebars->47->2914"
] ]
@ -31158,6 +31184,8 @@
{ {
"bs": "Idi na prvu stranicu", "bs": "Idi na prvu stranicu",
"en": "Go to first page", "en": "Go to first page",
"nl": "Ga naar de eerste pagina",
"pl": "Idź do pierwszej strony",
"xloc": [ "xloc": [
"default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons" "default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons"
] ]
@ -31165,6 +31193,8 @@
{ {
"bs": "Idi na posljednju stranicu", "bs": "Idi na posljednju stranicu",
"en": "Go to last page", "en": "Go to last page",
"nl": "Ga naar de laatste pagina ",
"pl": "Idź do ostatniej strony",
"xloc": [ "xloc": [
"default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons" "default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons"
] ]
@ -31226,6 +31256,8 @@
{ {
"bs": "Idi na sljedeću stranicu", "bs": "Idi na sljedeću stranicu",
"en": "Go to next page", "en": "Go to next page",
"nl": "Ga naar de volgende pagina",
"pl": "Idź do następnej strony",
"xloc": [ "xloc": [
"default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons" "default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons"
] ]
@ -31233,6 +31265,8 @@
{ {
"bs": "Idi na prethodnu stranicu", "bs": "Idi na prethodnu stranicu",
"en": "Go to previous page", "en": "Go to previous page",
"nl": "Ga naar de vorige pagina",
"pl": "Idź do poprzedniej strony",
"xloc": [ "xloc": [
"default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons" "default.handlebars->container->column_l->p1->p1title->devListToolbarViewIcons"
] ]
@ -31620,6 +31654,8 @@
{ {
"bs": "Tip grupe", "bs": "Tip grupe",
"en": "Group Type", "en": "Group Type",
"nl": "Groepstype",
"pl": "Typ Grupy",
"xloc": [ "xloc": [
"default.handlebars->47->2576" "default.handlebars->47->2576"
] ]
@ -32022,6 +32058,23 @@
{ {
"bs": "HTTP/", "bs": "HTTP/",
"en": "HTTP/", "en": "HTTP/",
"nl": "HTTP/",
"cs": "HTTP/",
"es": "HTTP/",
"de": "HTTP/",
"da": "HTTP/",
"fi": "HTTP/",
"fr": "HTTP/",
"hi": "HTTP/",
"it": "HTTP/",
"ja": "HTTP/",
"ko": "HTTP/",
"pt": "HTTP/",
"pt-br": "HTTP/",
"pl": "HTTP/",
"sv": "HTTP/",
"ru": "HTTP/",
"tr": "HTTP/",
"xloc": [ "xloc": [
"default.handlebars->47->1004", "default.handlebars->47->1004",
"default.handlebars->47->1981" "default.handlebars->47->1981"
@ -32030,6 +32083,8 @@
{ {
"bs": "HTTP/{0} link", "bs": "HTTP/{0} link",
"en": "HTTP/{0} link", "en": "HTTP/{0} link",
"nl": "HTTP/{0} link",
"pl": "HTTP/{0} link",
"xloc": [ "xloc": [
"default.handlebars->47->298" "default.handlebars->47->298"
] ]
@ -32116,6 +32171,23 @@
{ {
"bs": "HTTPS/", "bs": "HTTPS/",
"en": "HTTPS/", "en": "HTTPS/",
"nl": "HTTPS/",
"cs": "HTTPS/",
"es": "HTTPS/",
"de": "HTTPS/",
"da": "HTTPS/",
"fi": "HTTPS/",
"fr": "HTTPS/",
"hi": "HTTPS/",
"it": "HTTPS/",
"ja": "HTTPS/",
"ko": "HTTPS/",
"pt": "HTTPS/",
"pt-br": "HTTPS/",
"sv": "HTTPS/",
"ru": "HTTPS/",
"tr": "HTTPS/",
"pl": "HTTPS/",
"xloc": [ "xloc": [
"default.handlebars->47->1005", "default.handlebars->47->1005",
"default.handlebars->47->1982" "default.handlebars->47->1982"
@ -32124,6 +32196,23 @@
{ {
"bs": "HTTPS/{0}", "bs": "HTTPS/{0}",
"en": "HTTPS/{0}", "en": "HTTPS/{0}",
"nl": "HTTPS/{0}",
"pl": "HTTPS/{0}",
"cs": "HTTPS/{0}",
"es": "HTTPS/{0}",
"de": "HTTPS/{0}",
"da": "HTTPS/{0}",
"fi": "HTTPS/{0}",
"fr": "HTTPS/{0}",
"hi": "HTTPS/{0}",
"it": "HTTPS/{0}",
"ja": "HTTPS/{0}",
"ko": "HTTPS/{0}",
"pt": "HTTPS/{0}",
"pt-br": "HTTPS/{0}",
"sv": "HTTPS/{0}",
"ru": "HTTPS/{0}",
"tr": "HTTPS/{0}",
"xloc": [ "xloc": [
"default.handlebars->47->299" "default.handlebars->47->299"
] ]
@ -32524,6 +32613,8 @@
{ {
"bs": "Zahtjevi za pomoć", "bs": "Zahtjevi za pomoć",
"en": "Help requests", "en": "Help requests",
"nl": "Hulpverzoeken",
"pl": "Prośby pomocy",
"xloc": [ "xloc": [
"default.handlebars->47->1027", "default.handlebars->47->1027",
"default.handlebars->47->2179" "default.handlebars->47->2179"
@ -33126,6 +33217,7 @@
"bs": "Zapisi informacija o IP lokaciji", "bs": "Zapisi informacija o IP lokaciji",
"en": "IP location information records", "en": "IP location information records",
"nl": "IP locatiegegevens vermeldingen", "nl": "IP locatiegegevens vermeldingen",
"pl": "Zapisy o informacji lokalizacji IP",
"xloc": [ "xloc": [
"default.handlebars->47->2908" "default.handlebars->47->2908"
] ]
@ -35244,6 +35336,8 @@
{ {
"bs": "Intel&reg; AMT Uključite BIOS", "bs": "Intel&reg; AMT Uključite BIOS",
"en": "Intel&reg; AMT Power on to BIOS", "en": "Intel&reg; AMT Power on to BIOS",
"nl": "Intel&reg; AMT opstarten naar de BIOS",
"pl": "Intel&reg; AMT Uruchom do BIOS",
"xloc": [ "xloc": [
"default.handlebars->47->1145" "default.handlebars->47->1145"
] ]
@ -35306,6 +35400,8 @@
{ {
"bs": "Intel&reg; AMT Resetujte BIOS", "bs": "Intel&reg; AMT Resetujte BIOS",
"en": "Intel&reg; AMT Reset to BIOS", "en": "Intel&reg; AMT Reset to BIOS",
"nl": "Intel&reg; AMT reset naar de BIOS",
"pl": "Intel&reg; AMT Resetuj do BIOS",
"xloc": [ "xloc": [
"default.handlebars->47->1144" "default.handlebars->47->1144"
] ]
@ -38838,6 +38934,7 @@
"bs": "Zabilježeno vrijeme posljednje veze", "bs": "Zabilježeno vrijeme posljednje veze",
"en": "Last connection time records", "en": "Last connection time records",
"nl": "Laatste verbindingstijd vermeldingen", "nl": "Laatste verbindingstijd vermeldingen",
"pl": "Zapisy czasu ostatnich połączeń",
"xloc": [ "xloc": [
"default.handlebars->47->2912" "default.handlebars->47->2912"
] ]
@ -45805,6 +45902,7 @@
"bs": "Zapisi informacija o mrežnom interfejsu", "bs": "Zapisi informacija o mrežnom interfejsu",
"en": "Network interface information records", "en": "Network interface information records",
"nl": "Netwerkinterface informatie vermeldingen", "nl": "Netwerkinterface informatie vermeldingen",
"pl": "Zapisy informacji o interfejsach sieciowych",
"xloc": [ "xloc": [
"default.handlebars->47->2910" "default.handlebars->47->2910"
] ]
@ -51426,6 +51524,8 @@
{ {
"bs": "Uključite Intel&reg; AMT napajanje u BIOS?", "bs": "Uključite Intel&reg; AMT napajanje u BIOS?",
"en": "Perform Intel&reg; AMT power on to BIOS?", "en": "Perform Intel&reg; AMT power on to BIOS?",
"nl": "Perform Intel&reg; AMT opstarten naar de BIOS?",
"pl": "Czy wykonać Intel&reg; AMT uruchomienie do BIOS?",
"xloc": [ "xloc": [
"default.handlebars->47->1168" "default.handlebars->47->1168"
] ]
@ -51460,6 +51560,8 @@
{ {
"bs": "Izvršiti Intel&reg; AMT resetovanje na BIOS?", "bs": "Izvršiti Intel&reg; AMT resetovanje na BIOS?",
"en": "Perform Intel&reg; AMT reset to BIOS?", "en": "Perform Intel&reg; AMT reset to BIOS?",
"nl": "Perform Intel&reg; AMT resetten naar de BIOS?",
"pl": "Czy wykonać Intel&reg; AMT resetowanie do BIOS?",
"xloc": [ "xloc": [
"default.handlebars->47->1170" "default.handlebars->47->1170"
] ]
@ -52321,6 +52423,8 @@
{ {
"bs": "Port", "bs": "Port",
"en": "Port", "en": "Port",
"nl": "Poort",
"pl": "Port",
"xloc": [ "xloc": [
"default.handlebars->47->1126", "default.handlebars->47->1126",
"default.handlebars->47->1127" "default.handlebars->47->1127"
@ -57733,6 +57837,8 @@
{ {
"bs": "Zahtjev:", "bs": "Zahtjev:",
"en": "Request:", "en": "Request:",
"nl": "Verzoek:",
"pl": "Prośba:",
"xloc": [ "xloc": [
"device-help.html->2->5" "device-help.html->2->5"
] ]
@ -57740,6 +57846,8 @@
{ {
"bs": "Zahtjev: \"[[[UPIT ZA POMOĆ]]]\"", "bs": "Zahtjev: \"[[[UPIT ZA POMOĆ]]]\"",
"en": "Request: \"[[[HELPREQUEST]]]\"", "en": "Request: \"[[[HELPREQUEST]]]\"",
"nl": "Verzoek: \"[[[HELPREQUEST]]]\"",
"pl": "Prośba: \"[[[HELPREQUEST]]]\"",
"xloc": [ "xloc": [
"device-help.txt" "device-help.txt"
] ]
@ -58650,6 +58758,7 @@
"bs": "Trči", "bs": "Trči",
"en": "Run", "en": "Run",
"nl": "Uitvoeren", "nl": "Uitvoeren",
"pl": "Wykonaj",
"xloc": [ "xloc": [
"default.handlebars->47->924" "default.handlebars->47->924"
] ]
@ -58712,6 +58821,7 @@
"bs": "Pokrenite skriptu na ovom računaru", "bs": "Pokrenite skriptu na ovom računaru",
"en": "Run a script on this computer", "en": "Run a script on this computer",
"nl": "Voer een script uit op deze computer", "nl": "Voer een script uit op deze computer",
"pl": "Wykonaj skrypt na tym komputerze",
"xloc": [ "xloc": [
"default.handlebars->container->column_l->p11->deskarea0->deskarea4->1" "default.handlebars->container->column_l->p11->deskarea0->deskarea4->1"
] ]
@ -62381,6 +62491,7 @@
"bs": "Server ne može preuzeti snimke iz baze podataka.", "bs": "Server ne može preuzeti snimke iz baze podataka.",
"en": "Server is unable to get recordings from the database.", "en": "Server is unable to get recordings from the database.",
"nl": "Server kan geen opnamen uit de database halen.", "nl": "Server kan geen opnamen uit de database halen.",
"pl": "Serwer nie może pobrać zapisów z bazy danych.",
"xloc": [ "xloc": [
"default.handlebars->47->2797" "default.handlebars->47->2797"
] ]
@ -62389,6 +62500,7 @@
"bs": "Server ne može čitati iz foldera sa snimcima.", "bs": "Server ne može čitati iz foldera sa snimcima.",
"en": "Server is unable to read from the recordings folder.", "en": "Server is unable to read from the recordings folder.",
"nl": "Server kan niet lezen uit de opnamemap.", "nl": "Server kan niet lezen uit de opnamemap.",
"pl": "Serwer nie może odczytać zapisów z folderu.",
"xloc": [ "xloc": [
"default.handlebars->47->2796" "default.handlebars->47->2796"
] ]
@ -62397,6 +62509,7 @@
"bs": "Statistički zapisi servera", "bs": "Statistički zapisi servera",
"en": "Server statistics records", "en": "Server statistics records",
"nl": "Server statistieken vermeldingen", "nl": "Server statistieken vermeldingen",
"pl": "Zapisy statystyk serwera",
"xloc": [ "xloc": [
"default.handlebars->47->2915" "default.handlebars->47->2915"
] ]
@ -68186,6 +68299,7 @@
"bs": "Zapisi tekstualnih bilješki", "bs": "Zapisi tekstualnih bilješki",
"en": "Text notes records", "en": "Text notes records",
"nl": "Tekst notities vermeldingen", "nl": "Tekst notities vermeldingen",
"pl": "Zapisy notatek tekstowych",
"xloc": [ "xloc": [
"default.handlebars->47->2909" "default.handlebars->47->2909"
] ]
@ -68580,6 +68694,8 @@
{ {
"bs": "Ova verzija NodeJS-a ne podržava OpenID.", "bs": "Ova verzija NodeJS-a ne podržava OpenID.",
"en": "This NodeJS version does not support OpenID.", "en": "This NodeJS version does not support OpenID.",
"nl": "Deze NodeJS-versie ondersteunt OpenID niet.",
"pl": "Obecna wersja NodeJS nie wspiera OpenID.",
"xloc": [ "xloc": [
"default.handlebars->47->107" "default.handlebars->47->107"
] ]
@ -71483,6 +71599,7 @@
"bs": "Nije moguće učitati fajl ikone agenta: {0}.", "bs": "Nije moguće učitati fajl ikone agenta: {0}.",
"en": "Unable to load agent icon file: {0}.", "en": "Unable to load agent icon file: {0}.",
"nl": "Kan agent pictogram bestand niet laden: {0}.", "nl": "Kan agent pictogram bestand niet laden: {0}.",
"pl": "Nie moge załadować pliku ikony agenta: {0}.",
"xloc": [ "xloc": [
"default.handlebars->47->105" "default.handlebars->47->105"
] ]
@ -71491,6 +71608,7 @@
"bs": "Nije moguće učitati fajl logotipa agenta: {0}.", "bs": "Nije moguće učitati fajl logotipa agenta: {0}.",
"en": "Unable to load agent logo file: {0}.", "en": "Unable to load agent logo file: {0}.",
"nl": "Kan agent logo bestand niet laden: {0}.", "nl": "Kan agent logo bestand niet laden: {0}.",
"pl": "Nie moge załadować pliku logo agenta: {0}.",
"xloc": [ "xloc": [
"default.handlebars->47->106" "default.handlebars->47->106"
] ]
@ -73211,6 +73329,8 @@
{ {
"bs": "Dnevnik provjere autentičnosti korisnika", "bs": "Dnevnik provjere autentičnosti korisnika",
"en": "User Authentication Log", "en": "User Authentication Log",
"nl": "Gebruikersauthenticatielogboek",
"pl": "Dziennik Autentykacji Użytkownika",
"xloc": [ "xloc": [
"default.handlebars->47->3053" "default.handlebars->47->3053"
] ]
@ -73939,6 +74059,7 @@
"bs": "Zapisi grupe korisnika", "bs": "Zapisi grupe korisnika",
"en": "User group records", "en": "User group records",
"nl": "Gebruikersgroep vermeldingen", "nl": "Gebruikersgroep vermeldingen",
"pl": "Zapisy grupy użytkownika",
"xloc": [ "xloc": [
"default.handlebars->47->2916" "default.handlebars->47->2916"
] ]
@ -74056,6 +74177,7 @@
"bs": "Korisnički zapisi", "bs": "Korisnički zapisi",
"en": "User records", "en": "User records",
"nl": "Gebruikers vermeldingen", "nl": "Gebruikers vermeldingen",
"pl": "Zapisy użytkownika",
"xloc": [ "xloc": [
"default.handlebars->47->2906" "default.handlebars->47->2906"
] ]
@ -74090,6 +74212,8 @@
{ {
"bs": "Korisnik:", "bs": "Korisnik:",
"en": "User:", "en": "User:",
"nl": "Gebruiker:",
"pl": "Użytkownik:",
"xloc": [ "xloc": [
"device-help.html->2->5" "device-help.html->2->5"
] ]
@ -74097,6 +74221,8 @@
{ {
"bs": "Korisnik: \"[[[IME POMOĆI]]]\"", "bs": "Korisnik: \"[[[IME POMOĆI]]]\"",
"en": "User: \"[[[HELPUSERNAME]]]\"", "en": "User: \"[[[HELPUSERNAME]]]\"",
"nl": "Gebruiker: \"[[[HELPUSERNAME]]]\"",
"pl": "Użytkownik: \"[[[HELPUSERNAME]]]\"",
"xloc": [ "xloc": [
"device-help.txt" "device-help.txt"
] ]
@ -77959,6 +78085,8 @@
{ {
"bs": "[[[NAZIV UREĐAJA]]]", "bs": "[[[NAZIV UREĐAJA]]]",
"en": "[[[DEVICENAME]]]", "en": "[[[DEVICENAME]]]",
"nl": "[[[DEVICENAME]]]",
"pl": "[[[DEVICENAME]]]",
"xloc": [ "xloc": [
"device-help.html->2->3->1" "device-help.html->2->3->1"
] ]
@ -77992,6 +78120,22 @@
{ {
"bs": "[[[UPIT ZA POMOĆ]]]", "bs": "[[[UPIT ZA POMOĆ]]]",
"en": "[[[HELPREQUEST]]]", "en": "[[[HELPREQUEST]]]",
"nl": "[[[HELPREQUEST]]]",
"pl": "[[[HELPREQUEST]]]",
"cs": "[[[HELPREQUEST]]]",
"de": "[[[HELPREQUEST]]]",
"es": "[[[HELPREQUEST]]]",
"fi": "[[[HELPREQUEST]]]",
"it": "[[[HELPREQUEST]]]",
"hi": "[[[HELPREQUEST]]]",
"fr": "[[[HELPREQUEST]]]",
"ja": "[[[HELPREQUEST]]]",
"ko": "[[[HELPREQUEST]]]",
"pt": "[[[HELPREQUEST]]]",
"pt-br": "[[[HELPREQUEST]]]",
"ru": "[[[HELPREQUEST]]]",
"sv": "[[[HELPREQUEST]]]",
"tr": "[[[HELPREQUEST]]]",
"xloc": [ "xloc": [
"device-help.html->2->5->4" "device-help.html->2->5->4"
] ]
@ -77999,6 +78143,22 @@
{ {
"bs": "[[[IME POMOĆI]]]", "bs": "[[[IME POMOĆI]]]",
"en": "[[[HELPUSERNAME]]]", "en": "[[[HELPUSERNAME]]]",
"nl": "[[[HELPUSERNAME]]]",
"pl": "[[[HELPUSERNAME]]]",
"cs": "[[[HELPUSERNAME]]]",
"de": "[[[HELPUSERNAME]]]",
"es": "[[[HELPUSERNAME]]]",
"fi": "[[[HELPUSERNAME]]]",
"it": "[[[HELPUSERNAME]]]",
"hi": "[[[HELPUSERNAME]]]",
"fr": "[[[HELPUSERNAME]]]",
"ja": "[[[HELPUSERNAME]]]",
"ko": "[[[HELPUSERNAME]]]",
"pt": "[[[HELPUSERNAME]]]",
"pt-br": "[[[HELPUSERNAME]]]",
"ru": "[[[HELPUSERNAME]]]",
"sv": "[[[HELPUSERNAME]]]",
"tr": "[[[HELPUSERNAME]]]",
"xloc": [ "xloc": [
"device-help.html->2->5->1" "device-help.html->2->5->1"
] ]
@ -78034,6 +78194,8 @@
{ {
"bs": "[[[SERVERNAME]]] - \"[[[DEVICENAME]]]\" Zahtjev za pomoć", "bs": "[[[SERVERNAME]]] - \"[[[DEVICENAME]]]\" Zahtjev za pomoć",
"en": "[[[SERVERNAME]]] - \"[[[DEVICENAME]]]\" Help Request", "en": "[[[SERVERNAME]]] - \"[[[DEVICENAME]]]\" Help Request",
"nl": "[[[SERVERNAME]]] - \"[[[DEVICENAME]]]\" Verzoek om hulp",
"pl": "[[[SERVERNAME]]] - \"[[[DEVICENAME]]]\" Prośba Pomocy",
"xloc": [ "xloc": [
"device-help.html->0" "device-help.html->0"
] ]
@ -78150,6 +78312,8 @@
{ {
"bs": "[[[SERVERNAME]]] - Zahtjev za pomoć uređaja", "bs": "[[[SERVERNAME]]] - Zahtjev za pomoć uređaja",
"en": "[[[SERVERNAME]]] - Device Help Request", "en": "[[[SERVERNAME]]] - Device Help Request",
"nl": "[[[SERVERNAME]]] - Een verzoek om het apparaat te helpen",
"pl": "[[[SERVERNAME]]] - Prośba Pomocy Urządzenia",
"xloc": [ "xloc": [
"device-help.txt" "device-help.txt"
] ]
@ -78212,6 +78376,8 @@
{ {
"bs": "[[[SERVERNAME]]] - Zahtjev za pomoć", "bs": "[[[SERVERNAME]]] - Zahtjev za pomoć",
"en": "[[[SERVERNAME]]] - Help Request", "en": "[[[SERVERNAME]]] - Help Request",
"nl": "[[[SERVERNAME]]] - Verzoek om hulp",
"pl": "[[[SERVERNAME]]] - Prośba Pomocy",
"xloc": [ "xloc": [
"device-help.html->2->1->1->0->1->1" "device-help.html->2->1->1->0->1->1"
] ]
@ -78273,6 +78439,8 @@
{ {
"bs": "[[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]]", "bs": "[[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]]",
"en": "[[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]]", "en": "[[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]]",
"nl": "[[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]]",
"pl": "[[[SERVERURL]]]?viewmode=10&gotonode=[[[NODEID]]]",
"xloc": [ "xloc": [
"device-help.txt" "device-help.txt"
] ]
@ -80581,6 +80749,8 @@
{ {
"bs": "za navigaciju do ovog uređaja.", "bs": "za navigaciju do ovog uređaja.",
"en": "to navigate to this device.", "en": "to navigate to this device.",
"nl": "naar dit apparaat navigeren.",
"pl": "by nawigować do tego urządzenia.",
"xloc": [ "xloc": [
"device-help.html->2->7" "device-help.html->2->7"
] ]