mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-01-12 15:33:20 -05:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
78ebbc0188
@ -104,6 +104,7 @@
|
||||
<Compile Include="apfserver.js" />
|
||||
<Compile Include="exeHandler.js" />
|
||||
<Compile Include="letsencrypt.js" />
|
||||
<Compile Include="mcrec.js" />
|
||||
<Compile Include="meshaccelerator.js" />
|
||||
<Compile Include="meshctrl.js" />
|
||||
<Compile Include="meshmail.js" />
|
||||
@ -181,6 +182,181 @@
|
||||
<Content Include="public\clickonce\minirouter\publish.htm" />
|
||||
<Content Include="public\commander.htm" />
|
||||
<Content Include="public\compress.wcc" />
|
||||
<Content Include="public\email\account-check.html" />
|
||||
<Content Include="public\email\account-check.txt" />
|
||||
<Content Include="public\email\account-invite.html" />
|
||||
<Content Include="public\email\account-invite.txt" />
|
||||
<Content Include="public\email\account-login.html" />
|
||||
<Content Include="public\email\account-login.txt" />
|
||||
<Content Include="public\email\account-reset.html" />
|
||||
<Content Include="public\email\account-reset.txt" />
|
||||
<Content Include="public\email\mesh-invite.html" />
|
||||
<Content Include="public\email\mesh-invite.txt" />
|
||||
<Content Include="public\email\translations\account-check-min_cs.html" />
|
||||
<Content Include="public\email\translations\account-check-min_de.html" />
|
||||
<Content Include="public\email\translations\account-check-min_es.html" />
|
||||
<Content Include="public\email\translations\account-check-min_fr.html" />
|
||||
<Content Include="public\email\translations\account-check-min_hi.html" />
|
||||
<Content Include="public\email\translations\account-check-min_ja.html" />
|
||||
<Content Include="public\email\translations\account-check-min_ko.html" />
|
||||
<Content Include="public\email\translations\account-check-min_nl.html" />
|
||||
<Content Include="public\email\translations\account-check-min_pt.html" />
|
||||
<Content Include="public\email\translations\account-check-min_ru.html" />
|
||||
<Content Include="public\email\translations\account-check-min_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-check_cs.html" />
|
||||
<Content Include="public\email\translations\account-check_cs.txt" />
|
||||
<Content Include="public\email\translations\account-check_de.html" />
|
||||
<Content Include="public\email\translations\account-check_de.txt" />
|
||||
<Content Include="public\email\translations\account-check_es.html" />
|
||||
<Content Include="public\email\translations\account-check_es.txt" />
|
||||
<Content Include="public\email\translations\account-check_fr.html" />
|
||||
<Content Include="public\email\translations\account-check_fr.txt" />
|
||||
<Content Include="public\email\translations\account-check_hi.html" />
|
||||
<Content Include="public\email\translations\account-check_hi.txt" />
|
||||
<Content Include="public\email\translations\account-check_ja.html" />
|
||||
<Content Include="public\email\translations\account-check_ja.txt" />
|
||||
<Content Include="public\email\translations\account-check_ko.html" />
|
||||
<Content Include="public\email\translations\account-check_ko.txt" />
|
||||
<Content Include="public\email\translations\account-check_nl.html" />
|
||||
<Content Include="public\email\translations\account-check_nl.txt" />
|
||||
<Content Include="public\email\translations\account-check_pt.html" />
|
||||
<Content Include="public\email\translations\account-check_pt.txt" />
|
||||
<Content Include="public\email\translations\account-check_ru.html" />
|
||||
<Content Include="public\email\translations\account-check_ru.txt" />
|
||||
<Content Include="public\email\translations\account-check_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-check_zh-chs.txt" />
|
||||
<Content Include="public\email\translations\account-invite-min_cs.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_de.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_es.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_fr.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_hi.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_ja.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_ko.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_nl.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_pt.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_ru.html" />
|
||||
<Content Include="public\email\translations\account-invite-min_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-invite_cs.html" />
|
||||
<Content Include="public\email\translations\account-invite_cs.txt" />
|
||||
<Content Include="public\email\translations\account-invite_de.html" />
|
||||
<Content Include="public\email\translations\account-invite_de.txt" />
|
||||
<Content Include="public\email\translations\account-invite_es.html" />
|
||||
<Content Include="public\email\translations\account-invite_es.txt" />
|
||||
<Content Include="public\email\translations\account-invite_fr.html" />
|
||||
<Content Include="public\email\translations\account-invite_fr.txt" />
|
||||
<Content Include="public\email\translations\account-invite_hi.html" />
|
||||
<Content Include="public\email\translations\account-invite_hi.txt" />
|
||||
<Content Include="public\email\translations\account-invite_ja.html" />
|
||||
<Content Include="public\email\translations\account-invite_ja.txt" />
|
||||
<Content Include="public\email\translations\account-invite_ko.html" />
|
||||
<Content Include="public\email\translations\account-invite_ko.txt" />
|
||||
<Content Include="public\email\translations\account-invite_nl.html" />
|
||||
<Content Include="public\email\translations\account-invite_nl.txt" />
|
||||
<Content Include="public\email\translations\account-invite_pt.html" />
|
||||
<Content Include="public\email\translations\account-invite_pt.txt" />
|
||||
<Content Include="public\email\translations\account-invite_ru.html" />
|
||||
<Content Include="public\email\translations\account-invite_ru.txt" />
|
||||
<Content Include="public\email\translations\account-invite_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-invite_zh-chs.txt" />
|
||||
<Content Include="public\email\translations\account-login-min_cs.html" />
|
||||
<Content Include="public\email\translations\account-login-min_de.html" />
|
||||
<Content Include="public\email\translations\account-login-min_es.html" />
|
||||
<Content Include="public\email\translations\account-login-min_fr.html" />
|
||||
<Content Include="public\email\translations\account-login-min_hi.html" />
|
||||
<Content Include="public\email\translations\account-login-min_ja.html" />
|
||||
<Content Include="public\email\translations\account-login-min_ko.html" />
|
||||
<Content Include="public\email\translations\account-login-min_nl.html" />
|
||||
<Content Include="public\email\translations\account-login-min_pt.html" />
|
||||
<Content Include="public\email\translations\account-login-min_ru.html" />
|
||||
<Content Include="public\email\translations\account-login-min_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-login_cs.html" />
|
||||
<Content Include="public\email\translations\account-login_cs.txt" />
|
||||
<Content Include="public\email\translations\account-login_de.html" />
|
||||
<Content Include="public\email\translations\account-login_de.txt" />
|
||||
<Content Include="public\email\translations\account-login_es.html" />
|
||||
<Content Include="public\email\translations\account-login_es.txt" />
|
||||
<Content Include="public\email\translations\account-login_fr.html" />
|
||||
<Content Include="public\email\translations\account-login_fr.txt" />
|
||||
<Content Include="public\email\translations\account-login_hi.html" />
|
||||
<Content Include="public\email\translations\account-login_hi.txt" />
|
||||
<Content Include="public\email\translations\account-login_ja.html" />
|
||||
<Content Include="public\email\translations\account-login_ja.txt" />
|
||||
<Content Include="public\email\translations\account-login_ko.html" />
|
||||
<Content Include="public\email\translations\account-login_ko.txt" />
|
||||
<Content Include="public\email\translations\account-login_nl.html" />
|
||||
<Content Include="public\email\translations\account-login_nl.txt" />
|
||||
<Content Include="public\email\translations\account-login_pt.html" />
|
||||
<Content Include="public\email\translations\account-login_pt.txt" />
|
||||
<Content Include="public\email\translations\account-login_ru.html" />
|
||||
<Content Include="public\email\translations\account-login_ru.txt" />
|
||||
<Content Include="public\email\translations\account-login_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-login_zh-chs.txt" />
|
||||
<Content Include="public\email\translations\account-reset-min_cs.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_de.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_es.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_fr.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_hi.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_ja.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_ko.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_nl.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_pt.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_ru.html" />
|
||||
<Content Include="public\email\translations\account-reset-min_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-reset_cs.html" />
|
||||
<Content Include="public\email\translations\account-reset_cs.txt" />
|
||||
<Content Include="public\email\translations\account-reset_de.html" />
|
||||
<Content Include="public\email\translations\account-reset_de.txt" />
|
||||
<Content Include="public\email\translations\account-reset_es.html" />
|
||||
<Content Include="public\email\translations\account-reset_es.txt" />
|
||||
<Content Include="public\email\translations\account-reset_fr.html" />
|
||||
<Content Include="public\email\translations\account-reset_fr.txt" />
|
||||
<Content Include="public\email\translations\account-reset_hi.html" />
|
||||
<Content Include="public\email\translations\account-reset_hi.txt" />
|
||||
<Content Include="public\email\translations\account-reset_ja.html" />
|
||||
<Content Include="public\email\translations\account-reset_ja.txt" />
|
||||
<Content Include="public\email\translations\account-reset_ko.html" />
|
||||
<Content Include="public\email\translations\account-reset_ko.txt" />
|
||||
<Content Include="public\email\translations\account-reset_nl.html" />
|
||||
<Content Include="public\email\translations\account-reset_nl.txt" />
|
||||
<Content Include="public\email\translations\account-reset_pt.html" />
|
||||
<Content Include="public\email\translations\account-reset_pt.txt" />
|
||||
<Content Include="public\email\translations\account-reset_ru.html" />
|
||||
<Content Include="public\email\translations\account-reset_ru.txt" />
|
||||
<Content Include="public\email\translations\account-reset_zh-chs.html" />
|
||||
<Content Include="public\email\translations\account-reset_zh-chs.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_cs.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_de.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_es.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_fr.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_hi.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_ja.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_ko.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_nl.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_pt.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_ru.html" />
|
||||
<Content Include="public\email\translations\mesh-invite-min_zh-chs.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_cs.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_cs.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_de.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_de.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_es.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_es.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_fr.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_fr.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_hi.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_hi.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_ja.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_ja.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_ko.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_ko.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_nl.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_nl.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_pt.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_pt.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_ru.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_ru.txt" />
|
||||
<Content Include="public\email\translations\mesh-invite_zh-chs.html" />
|
||||
<Content Include="public\email\translations\mesh-invite_zh-chs.txt" />
|
||||
<Content Include="public\favicon.ico" />
|
||||
<Content Include="public\images-isdu\ComputerIcon.png" />
|
||||
<Content Include="public\images-isdu\ComputerIcon2.png" />
|
||||
@ -281,6 +457,7 @@
|
||||
<Content Include="views\download.handlebars" />
|
||||
<Content Include="views\error404-mobile.handlebars" />
|
||||
<Content Include="views\error404.handlebars" />
|
||||
<Content Include="views\invite.handlebars" />
|
||||
<Content Include="views\login-mobile.handlebars" />
|
||||
<Content Include="views\login.handlebars" />
|
||||
<Content Include="views\message.handlebars" />
|
||||
@ -301,6 +478,8 @@
|
||||
<Folder Include="public\clickonce\minirouter\" />
|
||||
<Folder Include="public\clickonce\minirouter\Application Files\" />
|
||||
<Folder Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\" />
|
||||
<Folder Include="public\email\" />
|
||||
<Folder Include="public\email\translations\" />
|
||||
<Folder Include="public\images-isdu" />
|
||||
<Folder Include="public\images\" />
|
||||
<Folder Include="public\scripts\" />
|
||||
@ -315,6 +494,7 @@
|
||||
<Folder Include="typings\" />
|
||||
<Folder Include="typings\globals\" />
|
||||
<Folder Include="typings\globals\connect-redis\" />
|
||||
<Folder Include="typings\globals\cookie-session\" />
|
||||
<Folder Include="typings\globals\express-handlebars\" />
|
||||
<Folder Include="typings\globals\express-session\" />
|
||||
<Folder Include="typings\globals\node-forge\" />
|
||||
@ -324,6 +504,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<TypeScriptCompile Include="typings\globals\connect-redis\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\cookie-session\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\express-handlebars\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\express-session\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\node-forge\index.d.ts" />
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
agents/meshagent_arm-linaro
Normal file
BIN
agents/meshagent_arm-linaro
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -153,8 +153,10 @@ function run(argv) {
|
||||
if ((typeof args.cdrom) == 'string') { settings.cdrom = args.cdrom; }
|
||||
if ((typeof args.tag) == 'string') { settings.tag = args.tag; }
|
||||
if ((typeof args.scan) == 'string') { settings.scan = args.scan; }
|
||||
if ((typeof args.token) == 'string') { settings.token = args.token; }
|
||||
if ((typeof args.timeout) == 'string') { settings.timeout = parseInt(args.timeout); }
|
||||
if ((typeof args.uuidoutput) == 'string' || args.uuidoutput) { settings.uuidoutput = args.uuidoutput; }
|
||||
if (args.emailtoken) { settings.emailtoken = true; }
|
||||
if (args.debug === true) { settings.debuglevel = 1; }
|
||||
if (args.debug) { try { waitForDebugger(); } catch (e) { } }
|
||||
if (args.noconsole) { settings.noconsole = true; }
|
||||
@ -591,10 +593,11 @@ function run(argv) {
|
||||
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
|
||||
if ((settings.hostname == null) || (typeof settings.hostname != 'string') || (settings.hostname == '')) { settings.hostname = '127.0.0.1'; }
|
||||
if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
|
||||
if ((settings.script == null) || (typeof settings.script != 'string') || (settings.script == '')) { if (mescriptJSON != '') { settings.scriptjson = mescriptJSON; } else { console.log('No or invalid \"script\" file specified, use --script [filename].'); exit(1); return; } }
|
||||
//if ((settings.script == null) || (typeof settings.script != 'string') || (settings.script == '')) { if (mescriptJSON != '') { settings.scriptjson = mescriptJSON; } else { console.log('No or invalid \"script\" file specified, use --script [filename].'); exit(1); return; } }
|
||||
if ((settings.script == null) || (typeof settings.script != 'string') || (settings.script == '')) { console.log('No or invalid \"script\" file specified, use --script [filename].'); exit(1); return; }
|
||||
startMeScript();
|
||||
} else if (settings.action == 'amtuuid') {
|
||||
// Start running
|
||||
// Start running
|
||||
if (settings.hostname != null) {
|
||||
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
|
||||
if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
|
||||
@ -1021,7 +1024,8 @@ function startMeshCommander() {
|
||||
} else {
|
||||
// If TLS is going to be used, setup a TLS socket
|
||||
var tls = require('tls');
|
||||
var tlsoptions = { host: webargs.host, port: webargs.port, secureProtocol: ((webargs.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), rejectUnauthorized: false };
|
||||
var tlsoptions = { host: webargs.host, port: webargs.port, rejectUnauthorized: false };
|
||||
if (webargs.tls1only == 1) { tlsoptions.secureProtocol = 'TLSv1_method'; }
|
||||
ws.forwardclient = tls.connect(tlsoptions, function () { debug(1, 'Connected TLS to ' + webargs.host + ':' + webargs.port + '.'); this.pipe(this.ws, { end: false }); this.ws.pipe(this, { end: false }); });
|
||||
ws.forwardclient.on('error', function () { debug(1, 'TLS connection error to ' + webargs.host + ':' + webargs.port + '.'); try { this.ws.end(); } catch (e) { } });
|
||||
ws.forwardclient.ws = ws;
|
||||
@ -2046,20 +2050,80 @@ function processLmsControlData(data) {
|
||||
//
|
||||
|
||||
function startRouter() {
|
||||
// Start by requesting a login token, this is needed because of 2FA and check that we have correct credentials from the start
|
||||
var options;
|
||||
try {
|
||||
var url = settings.serverurl.split('meshrelay.ashx').join('control.ashx') + '?user=' + settings.username + '&pass=' + settings.password;
|
||||
if (settings.emailtoken) { url += '&token=**email**'; } else if (settings.token != null) { url += '&token=' + settings.token; }
|
||||
options = http.parseUri(url);
|
||||
} catch (e) { console.log("Unable to parse \"serverUrl\"."); process.exit(1); return; }
|
||||
options.checkServerIdentity = onVerifyServer;
|
||||
options.rejectUnauthorized = false;
|
||||
settings.websocket = http.request(options);
|
||||
settings.websocket.upgrade = OnServerWebSocket;
|
||||
settings.websocket.on('error', function (e) { console.log("ERROR: " + JSON.stringify(e)); });
|
||||
settings.websocket.end();
|
||||
}
|
||||
|
||||
function OnServerWebSocket(msg, s, head) {
|
||||
settings.webchannel = s;
|
||||
s.on('data', function (msg) {
|
||||
var command = JSON.parse(msg);
|
||||
switch (command.action) {
|
||||
case 'close': {
|
||||
if (command.cause == 'noauth') {
|
||||
if (command.msg == 'tokenrequired') {
|
||||
if (command.email2fasent === true) {
|
||||
console.log("Login token email sent.");
|
||||
} else if (command.email2fa === true) {
|
||||
console.log("Login token required, use --token [token], or --emailtoken get a token.");
|
||||
} else {
|
||||
console.log("Login token required, use --token [token].");
|
||||
}
|
||||
} else { console.log("Invalid username or password."); }
|
||||
} else { console.log("Server disconnected: " + command.msg); }
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
case 'serverinfo': {
|
||||
s.write("{\"action\":\"authcookie\"}"); // Ask for our first authentication cookie
|
||||
break;
|
||||
}
|
||||
case 'authcookie': {
|
||||
if (settings.acookie == null) {
|
||||
settings.acookie = command.cookie;
|
||||
settings.rcookie = command.rcookie;
|
||||
settings.renewCookieTimer = setInterval(function () { settings.webchannel.write("{\"action\":\"authcookie\"}"); }, 600000); // Ask for new cookie every 10 minutes
|
||||
startRouterEx();
|
||||
} else {
|
||||
settings.acookie = command.cookie;
|
||||
settings.rcookie = command.rcookie;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
s.on('error', function () { console.log("Server connection error."); process.exit(1); return; });
|
||||
s.on('close', function () { console.log("Server closed the connection."); process.exit(1); return; });
|
||||
}
|
||||
|
||||
function startRouterEx() {
|
||||
tcpserver = net.createServer(OnTcpClientConnected);
|
||||
tcpserver.on('error', function (e) { console.log("ERROR: " + JSON.stringify(e)); exit(0); return; });
|
||||
tcpserver.listen(settings.localport, function () {
|
||||
// We started listening.
|
||||
if (settings.remotetarget == null) {
|
||||
console.log('Redirecting local port ' + settings.localport + ' to remote port ' + settings.remoteport + '.');
|
||||
} else {
|
||||
console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotetarget + ':' + settings.remoteport + '.');
|
||||
}
|
||||
console.log("Press ctrl-c to exit.");
|
||||
try {
|
||||
tcpserver.listen(settings.localport, function () {
|
||||
// We started listening.
|
||||
if (settings.remotetarget == null) {
|
||||
console.log('Redirecting local port ' + settings.localport + ' to remote port ' + settings.remoteport + '.');
|
||||
} else {
|
||||
console.log('Redirecting local port ' + settings.localport + ' to ' + settings.remotetarget + ':' + settings.remoteport + '.');
|
||||
}
|
||||
console.log("Press ctrl-c to exit.");
|
||||
|
||||
// If settings has a "cmd", run it now.
|
||||
//process.exec("notepad.exe");
|
||||
});
|
||||
// If settings has a "cmd", run it now.
|
||||
//process.exec("notepad.exe");
|
||||
});
|
||||
} catch (ex) { console.log("Unable to bind to local TCP port " + settings.localport + "."); exit(1); return; }
|
||||
}
|
||||
|
||||
// Called when a TCP connect is received on the local port. Launch a tunnel.
|
||||
@ -2069,8 +2133,9 @@ function OnTcpClientConnected(c) {
|
||||
debug(1, "Client connected");
|
||||
c.on('end', function () { disconnectTunnel(this, this.websocket, "Client closed"); });
|
||||
c.pause();
|
||||
var options;
|
||||
try {
|
||||
options = http.parseUri(settings.serverurl + '?user=' + settings.username + '&pass=' + settings.password + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport + (settings.remotetarget == null ? '' : '&tcpaddr=' + settings.remotetarget));
|
||||
options = http.parseUri(settings.serverurl + '?auth=' + settings.acookie + '&nodeid=' + settings.remotenodeid + '&tcpport=' + settings.remoteport + (settings.remotetarget == null ? '' : '&tcpaddr=' + settings.remotetarget));
|
||||
} catch (e) { console.log("Unable to parse \"serverUrl\"."); process.exit(1); return; }
|
||||
options.checkServerIdentity = onVerifyServer;
|
||||
options.rejectUnauthorized = false;
|
||||
@ -2104,8 +2169,8 @@ function OnWebSocket(msg, s, head) {
|
||||
}
|
||||
}
|
||||
});
|
||||
s.on('error', function (msg) { disconnectTunnel(this.tcp, this, 'Websocket error'); });
|
||||
s.on('close', function (msg) { disconnectTunnel(this.tcp, this, 'Websocket closed'); });
|
||||
s.on('error', function () { disconnectTunnel(this.tcp, this, 'Websocket error'); });
|
||||
s.on('close', function () { disconnectTunnel(this.tcp, this, 'Websocket closed'); });
|
||||
s.parent = this;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,10 @@ var MESHRIGHT_NOTERMINAL = 512;
|
||||
var MESHRIGHT_NOFILES = 1024;
|
||||
var MESHRIGHT_NOAMT = 2048;
|
||||
var MESHRIGHT_LIMITEDINPUT = 4096;
|
||||
var MESHRIGHT_LIMITEVENTS = 8192;
|
||||
var MESHRIGHT_CHATNOTIFY = 16384;
|
||||
var MESHRIGHT_UNINSTALL = 32768;
|
||||
var MESHRIGHT_NODESKTOP = 65536;
|
||||
|
||||
function createMeshCore(agent) {
|
||||
var obj = {};
|
||||
@ -276,7 +280,8 @@ function createMeshCore(agent) {
|
||||
*/
|
||||
|
||||
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
|
||||
var meshCoreObj = { action: 'coreinfo', value: 'MeshCore v6', caps: 14 }; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript, 32 = Temporary Agent, 64 = Recovery Agent
|
||||
var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ? ('MeshCore CRC[' + crc32c(require('MeshAgent').coreHash) + ']') : ('MeshCore v6')), caps: 14 }; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript, 32 = Temporary Agent, 64 = Recovery Agent
|
||||
|
||||
|
||||
// Get the operating system description string
|
||||
try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; }); } catch (ex) { }
|
||||
@ -790,7 +795,7 @@ function createMeshCore(agent) {
|
||||
if (process.platform != 'win32') break;
|
||||
var p = require('user-sessions').enumerateUsers();
|
||||
p.sessionid = data.sessionid;
|
||||
p.then(function (u) { mesh.SendCommand({ action: 'msg', type: 'userSessions', sessionid: u.sessionid, data: u }); });
|
||||
p.then(function (u) { mesh.SendCommand({ action: 'msg', type: 'userSessions', sessionid: data.sessionid, data: u }); });
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -1328,7 +1333,7 @@ function createMeshCore(agent) {
|
||||
//this.write('MeshCore Terminal Hello');
|
||||
} else if (this.httprequest.protocol == 2) {
|
||||
// Check user access rights for desktop
|
||||
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) {
|
||||
if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
|
||||
// Disengage this tunnel, user does not have the rights to do this!!
|
||||
this.httprequest.protocol = 999999;
|
||||
this.httprequest.s.end();
|
||||
@ -1396,8 +1401,7 @@ function createMeshCore(agent) {
|
||||
if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
|
||||
this.httprequest.desktop.kvm.connectionCount++;
|
||||
this.httprequest.desktop.kvm.users.push(this.httprequest.username);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.httprequest.desktop.kvm.connectionCount = 1;
|
||||
this.httprequest.desktop.kvm.users = [this.httprequest.username];
|
||||
}
|
||||
@ -1505,7 +1509,6 @@ function createMeshCore(agent) {
|
||||
//this.write('MeshCore KVM Hello!1');
|
||||
|
||||
} else if (this.httprequest.protocol == 5) {
|
||||
|
||||
// Check user access rights for files
|
||||
if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
|
||||
// Disengage this tunnel, user does not have the rights to do this!!
|
||||
@ -1958,7 +1961,7 @@ function createMeshCore(agent) {
|
||||
var response = null;
|
||||
switch (cmd) {
|
||||
case 'help': { // Displays available commands
|
||||
var fin = '', f = '', availcommands = 'agentsize,version,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper';
|
||||
var fin = '', f = '', availcommands = 'startupoptions,alert,agentsize,version,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper';
|
||||
if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration'; }
|
||||
availcommands = availcommands.split(',').sort();
|
||||
while (availcommands.length > 0) {
|
||||
@ -1969,6 +1972,27 @@ function createMeshCore(agent) {
|
||||
response = "Available commands: \r\n" + fin + ".";
|
||||
break;
|
||||
}
|
||||
case 'startupoptions':
|
||||
response = JSON.stringify(require('MeshAgent').getStartupOptions());
|
||||
break;
|
||||
case 'alert':
|
||||
if (args['_'].length == 0)
|
||||
{
|
||||
response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = args['_'].join(' ').split(',');
|
||||
if(p.length<2)
|
||||
{
|
||||
response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
|
||||
}
|
||||
else
|
||||
{
|
||||
this._alert = require('message-box').create(p[0], p[1], p.length==3?parseInt(p[2]):9999,1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'agentsize':
|
||||
var actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
|
||||
if (process.platform == 'win32') {
|
||||
@ -2366,7 +2390,7 @@ function createMeshCore(agent) {
|
||||
break;
|
||||
}
|
||||
case 'info': { // Return information about the agent and agent core module
|
||||
response = 'Current Core: ' + meshCoreObj.value + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform: ' + process.platform + '.\r\nCapabilities: ' + meshCoreObj.caps + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
|
||||
response = 'Current Core: ' + meshCoreObj.value + '\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform: ' + process.platform + '.\r\nCapabilities: ' + meshCoreObj.caps + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
|
||||
if (amt != null) { response += '\r\nBuilt-in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amt.lmsstate] + '.'; }
|
||||
if (meshCoreObj.osdesc) { response += '\r\nOS: ' + meshCoreObj.osdesc + '.'; }
|
||||
response += '\r\nModules: ' + addedModules.join(', ') + '.';
|
||||
|
@ -75,7 +75,15 @@ CheckInstallAgent() {
|
||||
machineid=30
|
||||
else
|
||||
# Linux x86, 64 bit
|
||||
machineid=6
|
||||
bitlen=$( getconf LONG_BIT )
|
||||
if [ $bitlen == '32' ]
|
||||
then
|
||||
# 32 bit OS
|
||||
machineid=5
|
||||
else
|
||||
# 64 bit OS
|
||||
machineid=6
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if [ $machinetype == 'x86' ] || [ $machinetype == 'i686' ] || [ $machinetype == 'i586' ]
|
||||
|
@ -21,8 +21,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
// Construct a WSMAN communication object
|
||||
function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
|
||||
{
|
||||
function CreateWsmanComm(/*host, port, user, pass, tls, extra*/) {
|
||||
var obj = {};
|
||||
obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
|
||||
obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
|
||||
@ -31,15 +30,13 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
|
||||
obj.digest = null;
|
||||
obj.RequestCount = 0;
|
||||
|
||||
if (arguments.length == 1 && typeof(arguments[0] == 'object'))
|
||||
{
|
||||
if (arguments.length == 1 && typeof (arguments[0] == 'object')) {
|
||||
obj.host = arguments[0].host;
|
||||
obj.port = arguments[0].port;
|
||||
obj.authToken = arguments[0].authToken;
|
||||
obj.tls = arguments[0].tls;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
obj.host = arguments[0];
|
||||
obj.port = arguments[1];
|
||||
obj.user = arguments[2];
|
||||
@ -75,14 +72,10 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/)
|
||||
if (globalDebugFlags & 1) { console.log("SEND: " + postdata + "\r\n\r\n"); } // DEBUG
|
||||
|
||||
// We are in a DukTape environement
|
||||
if (obj.digest == null)
|
||||
{
|
||||
if (obj.authToken)
|
||||
{
|
||||
if (obj.digest == null) {
|
||||
if (obj.authToken) {
|
||||
obj.digest = require('http-digest').create({ authToken: obj.authToken });
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
obj.digest = require('http-digest').create(obj.user, obj.pass);
|
||||
}
|
||||
obj.digest.http = require('http');
|
||||
|
@ -191,6 +191,12 @@ function SMBiosTables()
|
||||
catch(e)
|
||||
{
|
||||
}
|
||||
try
|
||||
{
|
||||
if (JSON.stringify(r).length > 65535) { r = {}; }
|
||||
}
|
||||
catch(ee)
|
||||
{}
|
||||
return r;
|
||||
}
|
||||
this.processorInfo = function processorInfo(data) {
|
||||
|
@ -145,7 +145,6 @@ function WindowsConsole()
|
||||
this.TrayIcon.remove();
|
||||
handled = true;
|
||||
}
|
||||
//if (!handled) { console.log(msg); }
|
||||
}
|
||||
});
|
||||
retVal.remove = function remove()
|
||||
|
@ -401,7 +401,8 @@ function windows_terminal() {
|
||||
}
|
||||
}
|
||||
}
|
||||
this._WriteCharacter = function (key, bControlKey) {
|
||||
this._WriteCharacter = function (key, bControlKey)
|
||||
{
|
||||
var rec = GM.CreateVariable(20);
|
||||
rec.Deref(0, 2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType
|
||||
rec.Deref(4, 4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown
|
||||
@ -410,10 +411,10 @@ function windows_terminal() {
|
||||
rec.Deref(8, 2).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.wRepeatCount
|
||||
rec.Deref(10, 2).toBuffer().writeUInt16LE(this._user32.VkKeyScanA(key).Val); // rec.Event.KeyEvent.wVirtualKeyCode
|
||||
rec.Deref(12, 2).toBuffer().writeUInt16LE(this._user32.MapVirtualKeyA(this._user32.VkKeyScanA(key).Val, MAPVK_VK_TO_VSC).Val);
|
||||
|
||||
|
||||
var dwWritten = GM.CreateVariable(4);
|
||||
if (this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val == 0) { return (false); }
|
||||
|
||||
|
||||
rec.Deref(4, 4).toBuffer().writeUInt16LE(0); // rec.Event.KeyEvent.bKeyDown
|
||||
return (this._kernel32.WriteConsoleInputA(this._stdinput, rec, 1, dwWritten).Val != 0);
|
||||
}
|
||||
@ -478,23 +479,28 @@ function windows_terminal() {
|
||||
return (retVal);
|
||||
}
|
||||
|
||||
this._SendDataBuffer = function (data) {
|
||||
this._SendDataBuffer = function (data)
|
||||
{
|
||||
// { data, attributes, width, height, x, y }
|
||||
|
||||
var dy, line, attr;
|
||||
for (dy = 0; dy < data.height; ++dy) {
|
||||
line = data.data[dy];
|
||||
attr = data.attributes[dy];
|
||||
line.s = line.toString();
|
||||
|
||||
//line = data.data.slice(data.width * dy, (data.width * dy) + data.width);
|
||||
//attr = data.attributes.slice(data.width * dy, (data.width * dy) + data.width);
|
||||
this._stream.push(TranslateLine(data.x + 1, data.y + dy + 1, line, attr));
|
||||
if (this._stream != null)
|
||||
{
|
||||
var dy, line, attr;
|
||||
for (dy = 0; dy < data.height; ++dy)
|
||||
{
|
||||
line = data.data[dy];
|
||||
attr = data.attributes[dy];
|
||||
line.s = line.toString();
|
||||
|
||||
//line = data.data.slice(data.width * dy, (data.width * dy) + data.width);
|
||||
//attr = data.attributes.slice(data.width * dy, (data.width * dy) + data.width);
|
||||
this._stream.push(TranslateLine(data.x + 1, data.y + dy + 1, line, attr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._SendScroll = function _SendScroll(dx, dy) {
|
||||
if (this._scrollTimer) { return; }
|
||||
this._SendScroll = function _SendScroll(dx, dy)
|
||||
{
|
||||
if (this._scrollTimer || this._stream == null) { return; }
|
||||
|
||||
var info = GM.CreateVariable(22);
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); }
|
||||
|
@ -607,7 +607,7 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
||||
if (g_len > obj.iderinfo.readbfr) { len = obj.iderinfo.readbfr; }
|
||||
g_len -= len;
|
||||
g_lba += len;
|
||||
var buffer = new Buffer(len);
|
||||
var buffer = Buffer.alloc(len);
|
||||
fs.read(g_media, buffer, 0, len, lba, function (error, bytesRead, buffer) {
|
||||
obj.SendDataToHost(g_dev, (g_len == 0), buffer.toString('binary'), featureRegister & 1);
|
||||
if ((g_len > 0) && (g_reset == false)) {
|
||||
|
@ -150,7 +150,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 = { secureProtocol: ((obj.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), 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 };
|
||||
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 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(); });
|
||||
@ -207,7 +208,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 = { secureProtocol: ((obj.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), 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 };
|
||||
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'; }
|
||||
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 + '.');
|
||||
|
@ -167,46 +167,15 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
|
||||
obj.socketState = 1;
|
||||
obj.kerberosDone = 0;
|
||||
|
||||
if (obj.mode==1 ) { //Direct
|
||||
if (obj.xtls != 1) {
|
||||
// Connect without TLS
|
||||
obj.socket = new obj.net.Socket();
|
||||
obj.socket.setEncoding('binary');
|
||||
obj.socket.setTimeout(6000); // Set socket idle timeout
|
||||
obj.socket.on('data', obj.xxOnSocketData);
|
||||
obj.socket.on('close', obj.xxOnSocketClosed);
|
||||
obj.socket.on('timeout', obj.xxOnSocketClosed);
|
||||
obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
|
||||
} else {
|
||||
// Connect with TLS
|
||||
var options = { secureProtocol: ((obj.xtlsMethod == 0) ? 'SSLv23_method' : 'TLSv1_method'), 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.xtlsoptions) {
|
||||
if (obj.xtlsoptions.ca) options.ca = obj.xtlsoptions.ca;
|
||||
if (obj.xtlsoptions.cert) options.cert = obj.xtlsoptions.cert;
|
||||
if (obj.xtlsoptions.key) options.key = obj.xtlsoptions.key;
|
||||
obj.xtlsoptions = options;
|
||||
}
|
||||
obj.socket = obj.tls.connect(obj.port, obj.host, obj.xtlsoptions, obj.xxOnSocketConnected);
|
||||
obj.socket.setEncoding('binary');
|
||||
obj.socket.setTimeout(6000); // Set socket idle timeout
|
||||
obj.socket.on('data', obj.xxOnSocketData);
|
||||
obj.socket.on('close', obj.xxOnSocketClosed);
|
||||
obj.socket.on('timeout', obj.xxOnSocketClosed);
|
||||
obj.socket.on('error', function (e) { if (e.message && e.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
|
||||
}
|
||||
obj.socket.setNoDelay(true); // Disable nagle. We will encode each WSMAN request as a single send block and want to send it at once. This may help Intel AMT handle pipelining?
|
||||
} else if (obj.mode==2 || obj.mode==3) { // CIRA and APF
|
||||
if (obj.mode==2) { // CIRA
|
||||
if ((obj.parent != null) && (obj.mode === 2) || (obj.mode === 3)) { // CIRA and APF
|
||||
if (obj.mode == 2) { // CIRA
|
||||
var ciraconn = obj.parent.mpsserver.ciraConnections[obj.host];
|
||||
obj.socket = obj.parent.mpsserver.SetupCiraChannel(ciraconn, obj.port);
|
||||
} else { //APF
|
||||
} else { // APF
|
||||
var apfconn = obj.parent.apfserver.apfConnections[obj.host];
|
||||
obj.socket = obj.parent.apfserver.SetupCiraChannel(apfconn, obj.port);
|
||||
}
|
||||
obj.socket.onData = function (ccon, data) {
|
||||
obj.xxOnSocketData(data);
|
||||
}
|
||||
|
||||
obj.socket.onData = function (ccon, data) { obj.xxOnSocketData(data); }
|
||||
obj.socket.onStateChange = function (ccon, state) {
|
||||
if (state == 0) {
|
||||
try {
|
||||
@ -222,6 +191,36 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, parent,
|
||||
obj.xxOnSocketConnected();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Direct connection
|
||||
if (obj.xtls != 1) {
|
||||
// Connect without TLS
|
||||
obj.socket = new obj.net.Socket();
|
||||
obj.socket.setEncoding('binary');
|
||||
obj.socket.setTimeout(6000); // Set socket idle timeout
|
||||
obj.socket.on('data', obj.xxOnSocketData);
|
||||
obj.socket.on('close', obj.xxOnSocketClosed);
|
||||
obj.socket.on('timeout', obj.xxOnSocketClosed);
|
||||
obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
|
||||
} else {
|
||||
// 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, 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;
|
||||
if (obj.xtlsoptions.key) options.key = obj.xtlsoptions.key;
|
||||
obj.xtlsoptions = options;
|
||||
}
|
||||
obj.socket = obj.tls.connect(obj.port, obj.host, obj.xtlsoptions, obj.xxOnSocketConnected);
|
||||
obj.socket.setEncoding('binary');
|
||||
obj.socket.setTimeout(6000); // Set socket idle timeout
|
||||
obj.socket.on('data', obj.xxOnSocketData);
|
||||
obj.socket.on('close', obj.xxOnSocketClosed);
|
||||
obj.socket.on('timeout', obj.xxOnSocketClosed);
|
||||
obj.socket.on('error', function (e) { if (e.message && e.message.indexOf('sslv3 alert bad record mac') >= 0) { obj.xtlsMethod = 1 - obj.xtlsMethod; } });
|
||||
}
|
||||
obj.socket.setNoDelay(true); // Disable nagle. We will encode each WSMAN request as a single send block and want to send it at once. This may help Intel AMT handle pipelining?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -733,7 +733,7 @@ function AmtStackCreateService(wsmanStack) {
|
||||
e = null;
|
||||
try {
|
||||
es = atob(responses.Body['EventRecords'][i]);
|
||||
e = new Buffer(es);
|
||||
e = Buffer.from(es);
|
||||
} catch (ex) {
|
||||
console.log(ex + " " + responses.Body['EventRecords'][i])
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ module.exports.CreateAmtScanner = function (parent) {
|
||||
if (err == null && docs.length > 0) {
|
||||
for (var i in docs) {
|
||||
var doc = docs[i], host = doc.host.toLowerCase();
|
||||
const ciraConnection = obj.parent.mpsserver.ciraConnections[doc._id];
|
||||
const ciraConnection = obj.parent.mpsserver ? obj.parent.mpsserver.ciraConnections[doc._id] : null;
|
||||
if ((host != '127.0.0.1') && (host != '::1') && (host.toLowerCase() != 'localhost') && (ciraConnection == null)) {
|
||||
var scaninfo = obj.scanTable[doc._id];
|
||||
if (scaninfo == undefined) {
|
||||
@ -371,7 +371,9 @@ 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; }
|
||||
client = obj.tls.connect(port, host, scaninfo.tlsoption == 1 ? { secureProtocol: 'TLSv1_method', 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 } : { 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 }, function () { this.write('GET / HTTP/1.1\r\nhost: ' + host + '\r\n\r\n'); });
|
||||
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'; }
|
||||
client = obj.tls.connect(port, host, tlsOptions, function () { this.write('GET / HTTP/1.1\r\nhost: ' + host + '\r\n\r\n'); });
|
||||
}
|
||||
client.scaninfo = scaninfo;
|
||||
client.func = func;
|
||||
|
@ -200,12 +200,17 @@ module.exports.CertificateOperations = function (parent) {
|
||||
if (u.protocol == 'https:') {
|
||||
// Read the certificate from HTTPS
|
||||
if (hostname == null) { hostname = u.hostname; }
|
||||
const tlssocket = obj.tls.connect((u.port ? u.port : 443), u.hostname, { servername: hostname, rejectUnauthorized: false }, function () { this.xxcert = this.getPeerCertificate(); this.end(); });
|
||||
parent.debug('cert', "loadCertificate() - Loading certificate from " + u.hostname + ":" + (u.port ? u.port : 443) + ", Hostname: " + hostname + "...");
|
||||
const tlssocket = obj.tls.connect((u.port ? u.port : 443), u.hostname, { servername: hostname, rejectUnauthorized: false }, function () {
|
||||
this.xxcert = this.getPeerCertificate();
|
||||
parent.debug('cert', "loadCertificate() - TLS connected, " + ((this.xxcert != null) ? "got certificate." : "no certificate."));
|
||||
try { this.destroy(); } catch (ex) { }
|
||||
this.xxfunc(this.xxurl, (this.xxcert == null)?null:(this.xxcert.raw.toString('binary')), hostname, this.xxtag);
|
||||
});
|
||||
tlssocket.xxurl = url;
|
||||
tlssocket.xxfunc = func;
|
||||
tlssocket.xxtag = tag;
|
||||
tlssocket.on('end', function () { this.xxfunc(this.xxurl, this.xxcert.raw.toString('binary'), hostname, this.xxtag); });
|
||||
tlssocket.on('error', function () { this.xxfunc(this.xxurl, null, hostname, this.xxtag); });
|
||||
tlssocket.on('error', function (error) { try { this.destroy(); } catch (ex) { } parent.debug('cert', "loadCertificate() - TLS error: " + error); this.xxfunc(this.xxurl, null, hostname, this.xxtag); });
|
||||
} else if (u.protocol == 'file:') {
|
||||
// Read the certificate from a file
|
||||
obj.fs.readFile(url.substring(7), 'utf8', function (err, data) {
|
||||
@ -301,10 +306,8 @@ module.exports.CertificateOperations = function (parent) {
|
||||
var cert = obj.pki.createCertificate();
|
||||
cert.publicKey = keys.publicKey;
|
||||
cert.serialNumber = String(Math.floor((Math.random() * 100000) + 1));
|
||||
cert.validity.notBefore = new Date();
|
||||
cert.validity.notBefore.setFullYear(cert.validity.notBefore.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don"t reject this cert.
|
||||
cert.validity.notAfter = new Date();
|
||||
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
|
||||
cert.validity.notBefore = new Date(2018, 0, 1);
|
||||
cert.validity.notAfter = new Date(2049, 11, 31);
|
||||
if (addThumbPrintToName === true) { commonName += '-' + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: 'hex' }).substring(0, 6); }
|
||||
if (country == null) { country = "unknown"; }
|
||||
if (organization == null) { organization = "unknown"; }
|
||||
@ -325,10 +328,8 @@ module.exports.CertificateOperations = function (parent) {
|
||||
var cert = obj.pki.createCertificate();
|
||||
cert.publicKey = keys.publicKey;
|
||||
cert.serialNumber = String(Math.floor((Math.random() * 100000) + 1));
|
||||
cert.validity.notBefore = new Date();
|
||||
cert.validity.notBefore.setFullYear(cert.validity.notAfter.getFullYear() - 1); // Create a certificate that is valid one year before, to make sure out-of-sync clocks don"t reject this cert.
|
||||
cert.validity.notAfter = new Date();
|
||||
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
|
||||
cert.validity.notBefore = new Date(2018, 0, 1);
|
||||
cert.validity.notAfter = new Date(2049, 11, 31);
|
||||
if (addThumbPrintToName === true) { commonName += "-" + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: 'hex' }).substring(0, 6); }
|
||||
var attrs = [{ name: 'commonName', value: commonName }];
|
||||
if (country != null) { attrs.push({ name: 'countryName', value: country }); }
|
||||
@ -807,7 +808,7 @@ module.exports.CertificateOperations = function (parent) {
|
||||
accelerator.accid = acceleratorCreateCount;
|
||||
accelerator.on('message', function (message) {
|
||||
acceleratorMessage++;
|
||||
this.x.func(this.x.tag, message);
|
||||
if (this.x.func) { this.x.func(this.x.tag, message); }
|
||||
delete this.x;
|
||||
if (pendingAccelerator.length > 0) { this.send(this.x = pendingAccelerator.shift()); } else { freeAccelerators.push(this); }
|
||||
});
|
||||
@ -854,5 +855,24 @@ module.exports.CertificateOperations = function (parent) {
|
||||
}
|
||||
};
|
||||
|
||||
// Perform any general operation
|
||||
obj.acceleratorPerformOperation = function (operation, data, tag, func) {
|
||||
if (acceleratorTotalCount <= 1) {
|
||||
// No accelerators available
|
||||
require(program).processMessage({ action: operation, data: data, tag: tag, func: func });
|
||||
} else {
|
||||
var acc = obj.getAccelerator();
|
||||
if (acc == null) {
|
||||
// Add to pending accelerator workload
|
||||
acceleratorPerformSignaturePushFuncCall++;
|
||||
pendingAccelerator.push({ action: operation, data: data, tag: tag, func: func });
|
||||
} else {
|
||||
// Send to accelerator now
|
||||
acceleratorPerformSignatureRunFuncCall++;
|
||||
acc.send(acc.x = { action: operation, data: data, tag: tag, func: func });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
11
common.js
11
common.js
@ -26,8 +26,8 @@ module.exports.ShortToStr = function (v) { return String.fromCharCode((v >> 8) &
|
||||
module.exports.ShortToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); };
|
||||
module.exports.IntToStr = function (v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
|
||||
module.exports.IntToStrX = function (v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); };
|
||||
module.exports.MakeToArray = function (v) { if (!v || v == null || typeof v == "object") return v; return [v]; };
|
||||
module.exports.SplitArray = function (v) { return v.split(","); };
|
||||
module.exports.MakeToArray = function (v) { if (!v || v == null || typeof v == 'object') return v; return [v]; };
|
||||
module.exports.SplitArray = function (v) { return v.split(','); };
|
||||
module.exports.Clone = function (v) { return JSON.parse(JSON.stringify(v)); };
|
||||
module.exports.IsFilenameValid = (function () { var x1 = /^[^\\/:\*\?"<>\|]+$/, x2 = /^\./, x3 = /^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; return function isFilenameValid(fname) { return module.exports.validateString(fname, 1, 4096) && x1.test(fname) && !x2.test(fname) && !x3.test(fname) && (fname[0] != '.'); }; })();
|
||||
module.exports.makeFilename = function (v) { return v.split('\\').join('').split('/').join('').split(':').join('').split('*').join('').split('?').join('').split('"').join('').split('<').join('').split('>').join('').split('|').join('').split(' ').join('').split('\'').join(''); }
|
||||
@ -122,8 +122,8 @@ module.exports.parseNameValueList = function (list) {
|
||||
|
||||
// Compute the MD5 digest hash for a set of values
|
||||
module.exports.ComputeDigesthash = function (username, password, realm, method, path, qop, nonce, nc, cnonce) {
|
||||
var ha1 = crypto.createHash('md5').update(username + ":" + realm + ":" + password).digest("hex");
|
||||
var ha2 = crypto.createHash('md5').update(method + ":" + path).digest("hex");
|
||||
var ha1 = crypto.createHash('md5').update(username + ":" + realm + ":" + password).digest('hex');
|
||||
var ha2 = crypto.createHash('md5').update(method + ":" + path).digest('hex');
|
||||
return crypto.createHash('md5').update(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2).digest("hex");
|
||||
};
|
||||
|
||||
@ -147,6 +147,7 @@ module.exports.escapeFieldName = function (name) { if ((name.indexOf('%') == -1)
|
||||
module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
|
||||
|
||||
// Escape all links
|
||||
module.exports.escapeLinksFieldNameEx = function (docx) { if (docx.links == null) { return docx; } var doc = Object.assign({}, docx); doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } return doc; };
|
||||
module.exports.escapeLinksFieldName = function (docx) { var doc = Object.assign({}, docx); if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } } return doc; };
|
||||
module.exports.unEscapeLinksFieldName = function (doc) { if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; };
|
||||
//module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } return docs; };
|
||||
@ -251,7 +252,7 @@ module.exports.translationsToJson = function(t) {
|
||||
for (var i in arr) {
|
||||
var names = [], el = arr[i], el2 = {};
|
||||
for (var j in el) { names.push(j); }
|
||||
names.sort();
|
||||
names.sort(function (a, b) { if (a == b) { return 0; } if (a == 'xloc') { return 1; } if (b == 'xloc') { return -1; } return a - b });
|
||||
for (var j in names) { el2[names[j]] = el[names[j]]; }
|
||||
if (el2.xloc != null) { el2.xloc.sort(); }
|
||||
arr2.push(el2);
|
||||
|
121
db.js
121
db.js
@ -28,9 +28,9 @@
|
||||
module.exports.CreateDB = function (parent, func) {
|
||||
var obj = {};
|
||||
var Datastore = null;
|
||||
var expireEventsSeconds = (60 * 60 * 24 * 20); // By default, expire events after 20 days. (Seconds * Minutes * Hours * Days)
|
||||
var expirePowerEventsSeconds = (60 * 60 * 24 * 10); // By default, expire power events after 10 days. (Seconds * Minutes * Hours * Days)
|
||||
var expireServerStatsSeconds = (60 * 60 * 24 * 30); // By default, expire power events after 30 days. (Seconds * Minutes * Hours * Days)
|
||||
var expireEventsSeconds = (60 * 60 * 24 * 20); // By default, expire events after 20 days (1728000). (Seconds * Minutes * Hours * Days)
|
||||
var expirePowerEventsSeconds = (60 * 60 * 24 * 10); // By default, expire power events after 10 days (864000). (Seconds * Minutes * Hours * Days)
|
||||
var expireServerStatsSeconds = (60 * 60 * 24 * 30); // By default, expire power events after 30 days (2592000). (Seconds * Minutes * Hours * Days)
|
||||
const common = require('./common.js');
|
||||
obj.identifier = null;
|
||||
obj.dbKey = null;
|
||||
@ -42,7 +42,8 @@ module.exports.CreateDB = function (parent, func) {
|
||||
// Check if the database unique identifier is present
|
||||
// This is used to check that in server peering mode, everyone is using the same database.
|
||||
obj.Get('DatabaseIdentifier', function (err, docs) {
|
||||
if ((docs.length == 1) && (docs[0].value != null)) {
|
||||
if (err != null) { parent.debug('db', 'ERROR (Get DatabaseIdentifier): ' + err); }
|
||||
if ((err == null) && (docs.length == 1) && (docs[0].value != null)) {
|
||||
obj.identifier = docs[0].value;
|
||||
} else {
|
||||
obj.identifier = Buffer.from(require('crypto').randomBytes(48), 'binary').toString('hex');
|
||||
@ -52,8 +53,9 @@ module.exports.CreateDB = function (parent, func) {
|
||||
|
||||
// Load database schema version and check if we need to update
|
||||
obj.Get('SchemaVersion', function (err, docs) {
|
||||
if (err != null) { parent.debug('db', 'ERROR (Get SchemaVersion): ' + err); }
|
||||
var ver = 0;
|
||||
if (docs && docs.length == 1) { ver = docs[0].value; }
|
||||
if ((err == null) && (docs.length == 1)) { ver = docs[0].value; }
|
||||
if (ver == 1) { console.log('This is an unsupported beta 1 database, delete it to create a new one.'); process.exit(0); }
|
||||
|
||||
// TODO: Any schema upgrades here...
|
||||
@ -87,6 +89,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
|
||||
// Remove all objects that have a "meshid" that no longer points to a valid mesh.
|
||||
obj.GetAllType('mesh', function (err, docs) {
|
||||
if (err != null) { parent.debug('db', 'ERROR (GetAll mesh): ' + err); }
|
||||
var meshlist = [];
|
||||
if ((err == null) && (docs.length > 0)) { for (var i in docs) { meshlist.push(docs[i]._id); } }
|
||||
if ((obj.databaseType == 4) || (obj.databaseType == 5)) {
|
||||
@ -102,7 +105,8 @@ module.exports.CreateDB = function (parent, func) {
|
||||
|
||||
// Fix all of the creating & login to ticks by seconds, not milliseconds.
|
||||
obj.GetAllType('user', function (err, docs) {
|
||||
if (err == null && docs.length > 0) {
|
||||
if (err != null) { parent.debug('db', 'ERROR (GetAll user): ' + err); }
|
||||
if ((err == null) && (docs.length > 0)) {
|
||||
for (var i in docs) {
|
||||
var fixed = false;
|
||||
|
||||
@ -182,14 +186,14 @@ module.exports.CreateDB = function (parent, func) {
|
||||
// MongoDB
|
||||
obj.file.aggregate([{ "$group": { _id: "$type", count: { $sum: 1 } } }]).toArray(function (err, docs) {
|
||||
var counters = {}, totalCount = 0;
|
||||
for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } }
|
||||
if (err == null) { for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } } }
|
||||
func(counters);
|
||||
});
|
||||
} else if (obj.databaseType == 2) {
|
||||
// MongoJS
|
||||
obj.file.aggregate([{ "$group": { _id: "$type", count: { $sum: 1 } } }], function (err, docs) {
|
||||
var counters = {}, totalCount = 0;
|
||||
for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } }
|
||||
if (err == null) { for (var i in docs) { if (docs[i]._id != null) { counters[docs[i]._id] = docs[i].count; totalCount += docs[i].count; } } }
|
||||
func(counters);
|
||||
});
|
||||
} else if (obj.databaseType == 1) {
|
||||
@ -219,13 +223,14 @@ module.exports.CreateDB = function (parent, func) {
|
||||
}
|
||||
|
||||
// This is used to rate limit a number of operation per day. Returns a startValue each new days, but you can substract it and save the value in the db.
|
||||
obj.getValueOfTheDay = function (id, startValue, func) { obj.Get(id, function (err, docs) { var date = new Date(), t = date.toLocaleDateString(); if (docs.length == 1) { var r = docs[0]; if (r.day == t) { func({ _id: id, value: r.value, day: t }); return; } } func({ _id: id, value: startValue, day: t }); }); };
|
||||
obj.getValueOfTheDay = function (id, startValue, func) { obj.Get(id, function (err, docs) { var date = new Date(), t = date.toLocaleDateString(); if ((err == null) && (docs.length == 1)) { var r = docs[0]; if (r.day == t) { func({ _id: id, value: r.value, day: t }); return; } } func({ _id: id, value: startValue, day: t }); }); };
|
||||
obj.escapeBase64 = function escapeBase64(val) { return (val.replace(/\+/g, '@').replace(/\//g, '$')); }
|
||||
|
||||
// Encrypt an database object
|
||||
obj.performRecordEncryptionRecode = function (func) {
|
||||
var count = 0;
|
||||
obj.GetAllType('user', function (err, docs) {
|
||||
if (err != null) { parent.debug('db', 'ERROR (performRecordEncryptionRecode): ' + err); }
|
||||
if (err == null) { for (var i in docs) { count++; obj.Set(docs[i]); } }
|
||||
obj.GetAllType('node', function (err, docs) {
|
||||
if (err == null) { for (var i in docs) { count++; obj.Set(docs[i]); } }
|
||||
@ -236,7 +241,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
|
||||
// Encrypt an database object
|
||||
function performTypedRecordDecrypt(data) {
|
||||
if ((obj.dbRecordsDecryptKey == null) || (typeof data != 'object')) return data;
|
||||
if ((data == null) || (obj.dbRecordsDecryptKey == null) || (typeof data != 'object')) return data;
|
||||
for (var i in data) {
|
||||
if (data[i].type == 'user') {
|
||||
data[i] = performPartialRecordDecrypt(data[i]);
|
||||
@ -335,7 +340,9 @@ module.exports.CreateDB = function (parent, func) {
|
||||
}
|
||||
//sqlDbQuery('DROP DATABASE MeshCentral', null, function (err, docs) { console.log('DROP'); }); return;
|
||||
sqlDbQuery('USE meshcentral', null, function (err, docs) {
|
||||
if (err != null) { parent.debug('db', 'ERROR: USE meshcentral: ' + err); }
|
||||
if (err == null) { setupFunctions(func); } else {
|
||||
parent.debug('db', 'Creating database...');
|
||||
sqlDbBatchExec([
|
||||
'CREATE DATABASE meshcentral',
|
||||
// Main table
|
||||
@ -364,7 +371,10 @@ module.exports.CreateDB = function (parent, func) {
|
||||
'CREATE INDEX ndxsmbiosexpire ON meshcentral.smbios (expire)',
|
||||
// Plugins table
|
||||
'CREATE TABLE meshcentral.plugin (id INT NOT NULL AUTO_INCREMENT, doc JSON, PRIMARY KEY(id), CHECK (json_valid(doc)))'
|
||||
], function (err) { /*if (err != null) { console.log(err); }*/ setupFunctions(func); });
|
||||
], function (err) {
|
||||
if (err != null) { parent.debug('db', 'BatchSetupDb: ' + err); }
|
||||
setupFunctions(func);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (parent.args.mongodb) {
|
||||
@ -373,6 +383,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
require('mongodb').MongoClient.connect(parent.args.mongodb, { useNewUrlParser: true, useUnifiedTopology: true }, function (err, client) {
|
||||
if (err != null) { console.log("Unable to connect to database: " + err); process.exit(); return; }
|
||||
Datastore = client;
|
||||
parent.debug('db', 'Connected to MongoDB database...');
|
||||
|
||||
// Get the database name and setup the database client
|
||||
var dbname = 'meshcentral';
|
||||
@ -778,15 +789,31 @@ module.exports.CreateDB = function (parent, func) {
|
||||
// Database actions on the main collection (MariaDB or MySQL)
|
||||
obj.Set = function (value, func) {
|
||||
var extra = null, extraex = null;
|
||||
value = common.escapeLinksFieldNameEx(value);
|
||||
if (value.meshid) { extra = value.meshid; } else if (value.email) { extra = 'email/' + value.email; }
|
||||
if ((value.type == 'node') && (value.intelamt != null) && (value.intelamt.uuid != null)) { extraex = 'uuid/' + value.intelamt.uuid; }
|
||||
sqlDbQuery('REPLACE INTO meshcentral.main VALUE (?, ?, ?, ?, ?, ?)', [value._id, (value.type ? value.type : null), ((value.domain != null) ? value.domain : null), extra, extraex, JSON.stringify(performTypedRecordEncrypt(value))], func);
|
||||
}
|
||||
obj.Get = function (_id, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [_id], func); }
|
||||
obj.Get = function (_id, func) {
|
||||
sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [_id], function (err, docs) {
|
||||
if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
|
||||
func(_id, func);
|
||||
});
|
||||
}
|
||||
obj.GetAll = function (func) { sqlDbQuery('SELECT domain, doc FROM meshcentral.main', null, func); }
|
||||
obj.GetHash = function (id, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ?', [id], func); }
|
||||
obj.GetAllTypeNoTypeField = function (type, domain, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ?', [type, domain], function (err, docs) { for (var i in docs) { delete docs[i].type } func(err, docs); }); };
|
||||
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { if (id && (id != '')) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ? AND type = ? AND domain = ? AND extra IN (?)', [id, type, domain, meshes], function (err, docs) { for (var i in docs) { delete docs[i].type } func(err, docs); }); } else { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ? AND extra IN (?)', [type, domain, meshes], function (err, docs) { for (var i in docs) { delete docs[i].type } func(err, docs); }); } };
|
||||
obj.GetAllTypeNoTypeField = function (type, domain, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ?', [type, domain], function (err, docs) { if (err == null) { for (var i in docs) { delete docs[i].type } } func(err, docs); }); };
|
||||
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, extrasids, domain, type, id, func) {
|
||||
if (id && (id != '')) {
|
||||
sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id = ? AND type = ? AND domain = ? AND extra IN (?)', [id, type, domain, meshes], function (err, docs) { if (err == null) { for (var i in docs) { delete docs[i].type } } func(err, docs); });
|
||||
} else {
|
||||
if (extrasids == null) {
|
||||
sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ? AND extra IN (?)', [type, domain, meshes], function (err, docs) { if (err == null) { for (var i in docs) { delete docs[i].type } } func(err, docs); });
|
||||
} else {
|
||||
sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = ? AND domain = ? AND (extra IN (?) OR id IN (?))', [type, domain, meshes, extrasids], function (err, docs) { if (err == null) { for (var i in docs) { delete docs[i].type } } func(err, docs); });
|
||||
}
|
||||
}
|
||||
};
|
||||
obj.GetAllType = function (type, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = ?', [type], func); }
|
||||
obj.GetAllIdsOfType = function (ids, domain, type, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE id IN (?) AND domain = ? AND type = ?', [ids, domain, type], func); }
|
||||
obj.GetUserWithEmail = function (domain, email, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE domain = ? AND extra = ?', [domain, 'email/' + email], func); }
|
||||
@ -796,11 +823,11 @@ module.exports.CreateDB = function (parent, func) {
|
||||
obj.RemoveAllOfType = function (type, func) { sqlDbQuery('DELETE FROM meshcentral.main WHERE type = ?', [type], func); };
|
||||
obj.InsertMany = function (data, func) { var pendingOps = 0; for (var i in data) { pendingOps++; obj.Set(data[i], function () { if (--pendingOps == 0) { func(); } }); } };
|
||||
obj.RemoveMeshDocuments = function (id) { sqlDbQuery('DELETE FROM meshcentral.main WHERE extra = ?', [id], function () { sqlDbQuery('DELETE FROM meshcentral.main WHERE id = ?', ['nt' + id], func); } ); };
|
||||
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
|
||||
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
|
||||
obj.DeleteDomain = function (domain, func) { sqlDbQuery('DELETE FROM meshcentral.main WHERE domain = ?', [domain], func); };
|
||||
obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } };
|
||||
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
|
||||
obj.getLocalAmtNodes = function (func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE (type = "node") AND (extraex IS NOT NULL)', null, function (err, docs) { var r = []; for (var i in docs) { if (docs[i].host != null) { r.push(docs[i]); } } func(err, r); }); };
|
||||
obj.getLocalAmtNodes = function (func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE (type = "node") AND (extraex IS NOT NULL)', null, function (err, docs) { var r = []; if (err == null) { for (var i in docs) { if (docs[i].host != null) { r.push(docs[i]); } } } func(err, r); }); };
|
||||
obj.getAmtUuidMeshNode = function (meshid, uuid, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE meshid = ? AND extraex = ?', [meshid, 'uuid/' + uuid], func); };
|
||||
obj.getAmtUuidNode = function (uuid, func) { sqlDbQuery('SELECT doc FROM meshcentral.main WHERE type = "node" AND extraex = ?', ['uuid/' + uuid], func); };
|
||||
obj.isMaxType = function (max, type, domainid, func) { if (max == null) { func(false); } else { sqlDbExec('SELECT COUNT(id) FROM meshcentral.main WHERE domain = ? AND type = ?', [domainid, type], function (err, response) { func((response['COUNT(id)'] == null) || (response['COUNT(id)'] > max), response['COUNT(id)']) }); } }
|
||||
@ -904,12 +931,12 @@ module.exports.CreateDB = function (parent, func) {
|
||||
obj.getPlugins = function (func) { sqlDbQuery('SELECT doc FROM meshcentral.plugin', null, func); }; // Get all plugins
|
||||
obj.getPlugin = function (id, func) { sqlDbQuery('SELECT doc FROM meshcentral.plugin WHERE id = ?', [id], func); }; // Get plugin
|
||||
obj.deletePlugin = function (id, func) { sqlDbQuery('DELETE FROM meshcentral.plugin WHERE id = ?', [id], func); }; // Delete plugin
|
||||
obj.setPluginStatus = function (id, status, func) { obj.getPlugin(id, function (err, docs) { if (docs.length == 1) { docs[0].status = status; obj.updatePlugin(id, docs[0], func); } }); };
|
||||
obj.setPluginStatus = function (id, status, func) { obj.getPlugin(id, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].status = status; obj.updatePlugin(id, docs[0], func); } }); };
|
||||
obj.updatePlugin = function (id, args, func) { delete args._id; sqlDbQuery('REPLACE INTO meshcentral.plugin VALUE (?, ?)', [id, JSON.stringify(args)], func); };
|
||||
}
|
||||
} else if (obj.databaseType == 3) {
|
||||
// Database actions on the main collection (MongoDB)
|
||||
obj.Set = function (data, func) { obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); };
|
||||
obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); };
|
||||
obj.Get = function (id, func) {
|
||||
if (arguments.length > 2) {
|
||||
var parms = [func];
|
||||
@ -921,15 +948,31 @@ module.exports.CreateDB = function (parent, func) {
|
||||
userCallback.apply(obj, _func2.userArgs);
|
||||
};
|
||||
func2.userArgs = parms;
|
||||
obj.file.find({ _id: id }).toArray(function (err, docs) { func2(err, performTypedRecordDecrypt(docs)); });
|
||||
obj.file.find({ _id: id }).toArray(function (err, docs) {
|
||||
if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
|
||||
func2(err, performTypedRecordDecrypt(docs));
|
||||
});
|
||||
} else {
|
||||
obj.file.find({ _id: id }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
|
||||
obj.file.find({ _id: id }).toArray(function (err, docs) {
|
||||
if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
|
||||
func(err, performTypedRecordDecrypt(docs));
|
||||
});
|
||||
}
|
||||
};
|
||||
obj.GetAll = function (func) { obj.file.find({}).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetHash = function (id, func) { obj.file.find({ _id: id }).project({ _id: 0, hash: 1 }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }).project({ type: 0 }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { var x = { type: type, domain: domain, meshid: { $in: meshes } }; if (id) { x._id = id; } obj.file.find(x, { type: 0 }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, extrasids, domain, type, id, func) {
|
||||
if (extrasids == null) {
|
||||
var x = { type: type, domain: domain, meshid: { $in: meshes } };
|
||||
if (id) { x._id = id; }
|
||||
obj.file.find(x, { type: 0 }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
|
||||
} else {
|
||||
var x = { type: type, domain: domain, $or: [ { meshid: { $in: meshes } }, { _id: { $in: extrasids } } ] };
|
||||
if (id) { x._id = id; }
|
||||
obj.file.find(x, { type: 0 }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
|
||||
}
|
||||
};
|
||||
obj.GetAllType = function (type, func) { obj.file.find({ type: type }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }).project({ type: 0 }).toArray(function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
@ -939,7 +982,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
obj.RemoveAllOfType = function (type, func) { obj.file.deleteMany({ type: type }, { multi: true }, func); };
|
||||
obj.InsertMany = function (data, func) { obj.file.insertMany(data, func); };
|
||||
obj.RemoveMeshDocuments = function (id) { obj.file.deleteMany({ meshid: id }, { multi: true }); obj.file.deleteOne({ _id: 'nt' + id }); };
|
||||
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
|
||||
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
|
||||
obj.DeleteDomain = function (domain, func) { obj.file.deleteMany({ domain: domain }, { multi: true }, func); };
|
||||
obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } };
|
||||
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
|
||||
@ -1041,7 +1084,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
|
||||
} else {
|
||||
// Database actions on the main collection (NeDB and MongoJS)
|
||||
obj.Set = function (data, func) { var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); };
|
||||
obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); };
|
||||
obj.Get = function (id, func) {
|
||||
if (arguments.length > 2) {
|
||||
var parms = [func];
|
||||
@ -1053,15 +1096,36 @@ module.exports.CreateDB = function (parent, func) {
|
||||
userCallback.apply(obj, _func2.userArgs);
|
||||
};
|
||||
func2.userArgs = parms;
|
||||
obj.file.find({ _id: id }, function (err, docs) { func2(err, performTypedRecordDecrypt(docs)); });
|
||||
obj.file.find({ _id: id }, function (err, docs) {
|
||||
if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
|
||||
func2(err, performTypedRecordDecrypt(docs));
|
||||
});
|
||||
} else {
|
||||
obj.file.find({ _id: id }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
|
||||
obj.file.find({ _id: id }, function (err, docs) {
|
||||
if ((docs != null) && (docs.length > 0) && (docs[0].links != null)) { docs[0] = common.unEscapeLinksFieldName(docs[0]); }
|
||||
func(err, performTypedRecordDecrypt(docs));
|
||||
});
|
||||
}
|
||||
};
|
||||
obj.GetAll = function (func) { obj.file.find({}, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetHash = function (id, func) { obj.file.find({ _id: id }, { _id: 0, hash: 1 }, func); };
|
||||
obj.GetAllTypeNoTypeField = function (type, domain, func) { obj.file.find({ type: type, domain: domain }, { type: 0 }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) { var x = { type: type, domain: domain, meshid: { $in: meshes } }; if (id) { x._id = id; } obj.file.find(x, { type: 0 }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
//obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, domain, type, id, func) {
|
||||
//var x = { type: type, domain: domain, meshid: { $in: meshes } };
|
||||
//if (id) { x._id = id; }
|
||||
//obj.file.find(x, { type: 0 }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
|
||||
//};
|
||||
obj.GetAllTypeNoTypeFieldMeshFiltered = function (meshes, extrasids, domain, type, id, func) {
|
||||
if (extrasids == null) {
|
||||
var x = { type: type, domain: domain, meshid: { $in: meshes } };
|
||||
if (id) { x._id = id; }
|
||||
obj.file.find(x, { type: 0 }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
|
||||
} else {
|
||||
var x = { type: type, domain: domain, $or: [{ meshid: { $in: meshes } }, { _id: { $in: extrasids } }] };
|
||||
if (id) { x._id = id; }
|
||||
obj.file.find(x, { type: 0 }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); });
|
||||
}
|
||||
};
|
||||
obj.GetAllType = function (type, func) { obj.file.find({ type: type }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetAllIdsOfType = function (ids, domain, type, func) { obj.file.find({ type: type, domain: domain, _id: { $in: ids } }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
obj.GetUserWithEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email }, { type: 0 }, function (err, docs) { func(err, performTypedRecordDecrypt(docs)); }); };
|
||||
@ -1071,7 +1135,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); };
|
||||
obj.InsertMany = function (data, func) { obj.file.insert(data, func); };
|
||||
obj.RemoveMeshDocuments = function (id) { obj.file.remove({ meshid: id }, { multi: true }); obj.file.remove({ _id: 'nt' + id }); };
|
||||
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if (docs.length == 1) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
|
||||
obj.MakeSiteAdmin = function (username, domain) { obj.Get('user/' + domain + '/' + username, function (err, docs) { if ((err == null) && (docs.length == 1)) { docs[0].siteadmin = 0xFFFFFFFF; obj.Set(docs[0]); } }); };
|
||||
obj.DeleteDomain = function (domain, func) { obj.file.remove({ domain: domain }, { multi: true }, func); };
|
||||
obj.SetUser = function (user) { if (user.subscriptions != null) { var u = Clone(user); if (u.subscriptions) { delete u.subscriptions; } obj.Set(u); } else { obj.Set(user); } };
|
||||
obj.dispose = function () { for (var x in obj) { if (obj[x].close) { obj[x].close(); } delete obj[x]; } };
|
||||
@ -1236,7 +1300,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
var mongoDumpPath = 'mongodump';
|
||||
if (parent.config.settings.autobackup && parent.config.settings.autobackup.mongodumppath) { mongoDumpPath = parent.config.settings.autobackup.mongodumppath; }
|
||||
const child_process = require('child_process');
|
||||
const cmd = '\"' + mongoDumpPath + '\" --db=\"' + dbname + '\" --archive=\"' + newBackupPath + '.archive\"';
|
||||
var cmd = '\"' + mongoDumpPath + '\" --db=\"' + dbname + '\" --archive=\"' + newBackupPath + '.archive\"';
|
||||
if (dburl) { cmd = '\"' + mongoDumpPath + '\" --uri=\"' + dburl + '\" --archive=\"' + newBackupPath + '.archive\"'; }
|
||||
var backupProcess = child_process.exec(cmd, { cwd: backupPath }, function (error, stdout, stderr) {
|
||||
try {
|
||||
@ -1312,6 +1376,7 @@ module.exports.CreateDB = function (parent, func) {
|
||||
|
||||
// Called when a node has changed
|
||||
function dbNodeChange(nodeChange, added) {
|
||||
common.unEscapeLinksFieldName(nodeChange.fullDocument);
|
||||
const node = nodeChange.fullDocument;
|
||||
if (node.intelamt && node.intelamt.pass) { delete node.intelamt.pass; } // Remove the Intel AMT password before eventing this.
|
||||
parent.DispatchEvent(['*', node.meshid], obj, { etype: 'node', action: (added ? 'addnode' : 'changenode'), node: node, nodeid: node._id, domain: node.domain, nolog: 1 });
|
||||
|
15
emails/account-check.html
Normal file
15
emails/account-check.html
Normal file
@ -0,0 +1,15 @@
|
||||
<div>[[[SERVERNAME]]] - Email Verification</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8>
|
||||
<tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting email verification, click on the following link to complete the process.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Click here to verify your e-mail address.</a>
|
||||
</p>
|
||||
If you did not initiate this request, please ignore this mail.
|
||||
</div>
|
6
emails/account-check.txt
Normal file
6
emails/account-check.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Email Verification
|
||||
Hi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
If you did not initiate this request, please ignore this mail.
|
19
emails/account-invite.html
Normal file
19
emails/account-invite.html
Normal file
@ -0,0 +1,19 @@
|
||||
<div>[[[SERVERNAME]]] - Account Invitation</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8>
|
||||
<tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account Invitation</b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>An account was created for you on server <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, you can access it now with:</p>
|
||||
<p>
|
||||
Username: <b notrans="1">[[[ACCOUNTNAME]]]</b><br />
|
||||
Password: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Best regards,
|
||||
<br />
|
||||
[[[USERNAME]]]
|
||||
<br />
|
||||
</div>
|
5
emails/account-invite.txt
Normal file
5
emails/account-invite.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Account Invitation
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
Best regards,
|
||||
~[[[USERNAME]]]
|
12
emails/account-login.html
Normal file
12
emails/account-login.html
Normal file
@ -0,0 +1,12 @@
|
||||
<div>[[[SERVERNAME]]] - Account Login</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8>
|
||||
<tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account Login</b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Your login token is: [[[TOKEN]]]</p>
|
||||
<p>This token can only be used once and is valid for 5 minutes.</p>
|
||||
</div>
|
4
emails/account-login.txt
Normal file
4
emails/account-login.txt
Normal file
@ -0,0 +1,4 @@
|
||||
[[[SERVERNAME]]] - Account Login
|
||||
Your login token is: [[[TOKEN]]]
|
||||
~
|
||||
This token can only be used once and is valid for 5 minutes.
|
15
emails/account-reset.html
Normal file
15
emails/account-reset.html
Normal file
@ -0,0 +1,15 @@
|
||||
<div>[[[SERVERNAME]]] - Account Reset</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8>
|
||||
<tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting an account password reset, click on the following link to complete the process.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Click here to reset your account password.</a>
|
||||
</p>
|
||||
If you did not initiate this request, please ignore this mail.
|
||||
</div>
|
6
emails/account-reset.txt
Normal file
6
emails/account-reset.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Account Reset
|
||||
Hi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is requesting an account password reset. Nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
If you did not initiate this request, please ignore this mail.
|
42
emails/mesh-invite.html
Normal file
42
emails/mesh-invite.html
Normal file
@ -0,0 +1,42 @@
|
||||
<div>[[[SERVERNAME]]] - Invitation</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding=8>
|
||||
<tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Agent Installation</b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<area-name>
|
||||
<p>
|
||||
Hello [[[NAME]]],
|
||||
</p>
|
||||
</area-name>
|
||||
<p>User [[[USERNAME]]] on server <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting you to install software to start a remote control session.</p>
|
||||
<area-msg>
|
||||
<p>
|
||||
Message: <b notrans="1">[[[MSG]]]</b>
|
||||
</p>
|
||||
</area-msg>
|
||||
<area-windows>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/meshagents?id=3&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&installflags=[[[INSTALLFLAGS]]]">Click here to download the MeshAgent for Windows.</a>
|
||||
</p>
|
||||
</area-windows>
|
||||
<area-osx>
|
||||
<p style="margin-left:30px"><a href="[[[SERVERURL]]]/meshagents?id=16&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&installflags=[[[INSTALLFLAGS]]]">Click here to download the MeshAgent for Apple OSX.</a></p>
|
||||
</area-osx>
|
||||
<area-linux>
|
||||
<p>
|
||||
For Linux, cut & paste the following in a terminal to install the agent:<br />
|
||||
<pre style="margin-left:30px" notrans="1">wget -q "[[[SERVERURL]]]/meshagents?script=1" --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh [[[SERVERURL]]] \'[[[MESHIDHEX]]]\'</pre>
|
||||
</p>
|
||||
</area-linux>
|
||||
<area-link>
|
||||
<p>
|
||||
To install the software, <a href="[[[SERVERURL]]][[[LINKURL]]]">click here</a> and follow the instructions.
|
||||
</p>
|
||||
</area-link>
|
||||
<p>If you did not initiate this request, please ignore this mail.</p>
|
||||
Best regards,<br>[[[USERNAME]]]<br>
|
||||
</div>
|
35
emails/mesh-invite.txt
Normal file
35
emails/mesh-invite.txt
Normal file
@ -0,0 +1,35 @@
|
||||
[[[SERVERNAME]]] - Invitation
|
||||
~<area-name>
|
||||
Hello [[[NAME]]],
|
||||
~</area-name>
|
||||
User [[[USERNAME]]] on server [[[SERVERNAME]]] ([[[SERVERURL]]]/) is requesting you install software to start the remote control session.
|
||||
~<area-msg>
|
||||
~
|
||||
Message: [[[MSG]]]
|
||||
~
|
||||
~</area-msg>
|
||||
~<area-windows>
|
||||
For Windows, nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/meshagents?id=3&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&installflags=[[[INSTALLFLAGS]]]
|
||||
~
|
||||
~</area-windows>
|
||||
~<area-osx>
|
||||
For Apple OSX, nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/meshagents?id=16&meshid=[[[MESHIDHEX]]]&tag=mailto:[[[EMAIL]]]&installflags=[[[INSTALLFLAGS]]]
|
||||
~
|
||||
~</area-osx>
|
||||
~<area-linux>
|
||||
For Linux, cut & paste the following in a terminal to install the agent:
|
||||
~
|
||||
~wget -q "[[[SERVERURL]]]/meshagents?script=1" --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh [[[SERVERURL]]] '[[[MESHIDHEX]]]'
|
||||
~
|
||||
~</area-linux>
|
||||
~<area-link>
|
||||
To install the software, navigate to [[[SERVERURL]]][[[LINKURL]]] and follow the instructions.
|
||||
~</area-link>
|
||||
If you did not initiate this request, please ignore this mail.
|
||||
~
|
||||
Best regards,
|
||||
~[[[USERNAME]]]
|
15
emails/translations/account-check_cs.html
Normal file
15
emails/translations/account-check_cs.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Ověření e-mailem</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Ověření</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Ahoj [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> požaduje ověření e-mailem a dokončete proces kliknutím na následující odkaz.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Kliknutím sem ověřte svou e-mailovou adresu.</a>
|
||||
</p>
|
||||
Pokud jste tento požadavek nezačali, ignorujte tento e-mail.
|
||||
</div></body></html>
|
6
emails/translations/account-check_cs.txt
Normal file
6
emails/translations/account-check_cs.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Ověření e-mailem
|
||||
Ahoj [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) provádí ověření e-mailem. Chcete-li proces dokončit, přejděte na následující odkaz:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
Pokud jste tento požadavek nezačali, ignorujte tento e-mail.
|
15
emails/translations/account-check_de.html
Normal file
15
emails/translations/account-check_de.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - E-Mail-Überprüfung</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Überprüfung</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Hallo [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> Wenn Sie eine E-Mail-Bestätigung anfordern, klicken Sie auf den folgenden Link, um den Vorgang abzuschließen.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Klicken Sie hier, um Ihre E-Mail-Adresse zu bestätigen.</a>
|
||||
</p>
|
||||
Wenn Sie diese Anfrage nicht initiiert haben, ignorieren Sie diese Mail bitte.
|
||||
</div></body></html>
|
6
emails/translations/account-check_de.txt
Normal file
6
emails/translations/account-check_de.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - E-Mail-Überprüfung
|
||||
Hallo [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) führt eine E-Mail-Überprüfung durch. Klicken Sie auf den folgenden Link, um den Vorgang abzuschließen:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
Wenn Sie diese Anfrage nicht initiiert haben, ignorieren Sie diese Mail bitte.
|
15
emails/translations/account-check_es.html
Normal file
15
emails/translations/account-check_es.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Email Verification</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting email verification, click on the following link to complete the process.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Click here to verify your e-mail address.</a>
|
||||
</p>
|
||||
If you did not initiate this request, please ignore this mail.
|
||||
</div></body></html>
|
6
emails/translations/account-check_es.txt
Normal file
6
emails/translations/account-check_es.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Email Verification
|
||||
Hi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
If you did not initiate this request, please ignore this mail.
|
15
emails/translations/account-check_fr.html
Normal file
15
emails/translations/account-check_fr.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Vérification E-mail</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Vérification</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Bonjour [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> demande une vérification par e-mail, cliquez sur le lien suivant pour terminer le processus.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Cliquez ici pour vérifier votre adresse e-mail.</a>
|
||||
</p>
|
||||
Si vous n'avez pas initié cette demande, veuillez ignorer ce courrier.
|
||||
</div></body></html>
|
6
emails/translations/account-check_fr.txt
Normal file
6
emails/translations/account-check_fr.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Vérification E-mail
|
||||
Bonjour [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) effectue une vérification par e-mail. Accédez au lien suivant pour terminer le processus:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
Si vous n'avez pas initié cette demande, veuillez ignorer ce courrier.
|
15
emails/translations/account-check_hi.html
Normal file
15
emails/translations/account-check_hi.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Email Verification</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting email verification, click on the following link to complete the process.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Click here to verify your e-mail address.</a>
|
||||
</p>
|
||||
If you did not initiate this request, please ignore this mail.
|
||||
</div></body></html>
|
6
emails/translations/account-check_hi.txt
Normal file
6
emails/translations/account-check_hi.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Email Verification
|
||||
Hi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
If you did not initiate this request, please ignore this mail.
|
15
emails/translations/account-check_ja.html
Normal file
15
emails/translations/account-check_ja.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]]-メールの確認</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]]-確認</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>[[[USERNAME]]]様 <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> がメールの確認をリクエストしている場合は、次のリンクをクリックしてプロセスを完了してください。</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">ここをクリックして、電子メールアドレスを確認してください。</a>
|
||||
</p>
|
||||
このリクエストを開始していない場合は、このメールを無視してください。
|
||||
</div></body></html>
|
6
emails/translations/account-check_ja.txt
Normal file
6
emails/translations/account-check_ja.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]]-メールの確認
|
||||
こんにちは[[[USERNAME]]]、[[[SERVERNAME]]]([[[SERVERURL]]])は電子メールの検証を実行しています。プロセスを完了するには、次のリンクに移動します。
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
このリクエストを開始していない場合は、このメールを無視してください。
|
15
emails/translations/account-check_ko.html
Normal file
15
emails/translations/account-check_ko.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Email Verification</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting email verification, click on the following link to complete the process.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Click here to verify your e-mail address.</a>
|
||||
</p>
|
||||
If you did not initiate this request, please ignore this mail.
|
||||
</div></body></html>
|
6
emails/translations/account-check_ko.txt
Normal file
6
emails/translations/account-check_ko.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Email Verification
|
||||
Hi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
If you did not initiate this request, please ignore this mail.
|
15
emails/translations/account-check_nl.html
Normal file
15
emails/translations/account-check_nl.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - E-mail Verificatie</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verificatie</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Hallo [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> vraagt om e-mailverificatie, klik op de volgende link om het proces te voltooien.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Klik hier om uw e-mailadres te verifiëren.</a>
|
||||
</p>
|
||||
Als u dit verzoek niet heeft ingediend, dan kunt u deze e-mail negeren.
|
||||
</div></body></html>
|
6
emails/translations/account-check_nl.txt
Normal file
6
emails/translations/account-check_nl.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - E-mail Verificatie
|
||||
Hallo [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) voert een e-mailverificatie uit. Ga naar de volgende link om het proces te voltooien:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
Als u dit verzoek niet heeft ingediend, dan kunt u deze e-mail negeren.
|
15
emails/translations/account-check_pt.html
Normal file
15
emails/translations/account-check_pt.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Email Verification</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Verification</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Hi [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> is requesting email verification, click on the following link to complete the process.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Click here to verify your e-mail address.</a>
|
||||
</p>
|
||||
If you did not initiate this request, please ignore this mail.
|
||||
</div></body></html>
|
6
emails/translations/account-check_pt.txt
Normal file
6
emails/translations/account-check_pt.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - Email Verification
|
||||
Hi [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) is performing an e-mail verification. Nagivate to the following link to complete the process:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
If you did not initiate this request, please ignore this mail.
|
15
emails/translations/account-check_ru.html
Normal file
15
emails/translations/account-check_ru.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - подтверждение по электронной почте</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Подтверждение</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Привет [[[USERNAME]]], <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> запрашивает подтверждение по электронной почте, нажмите на следующую ссылку, чтобы завершить процесс.</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">Нажмите здесь, чтобы подтвердить свой адрес электронной почты.</a>
|
||||
</p>
|
||||
Если вы не инициировали этот запрос, игнорируйте это письмо.
|
||||
</div></body></html>
|
6
emails/translations/account-check_ru.txt
Normal file
6
emails/translations/account-check_ru.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]] - подтверждение по электронной почте
|
||||
Здравствуйте, [[[USERNAME]]], [[[SERVERNAME]]] ([[[SERVERURL]]]) выполняет проверку электронной почты. Для завершения процесса перейдите по следующей ссылке:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
Если вы не инициировали этот запрос, игнорируйте это письмо.
|
15
emails/translations/account-check_zh-chs.html
Normal file
15
emails/translations/account-check_zh-chs.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]]-电子邮件验证</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]]-验证</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>[[[USERNAME]],你好, <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> 正在请求电子邮件验证,请单击以下链接以完成该过程。</p>
|
||||
<p style="margin-left:30px">
|
||||
<a href="[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]">单击此处以验证您的电子邮件地址。</a>
|
||||
</p>
|
||||
如果您没有发起此请求,请忽略此邮件。
|
||||
</div></body></html>
|
6
emails/translations/account-check_zh-chs.txt
Normal file
6
emails/translations/account-check_zh-chs.txt
Normal file
@ -0,0 +1,6 @@
|
||||
[[[SERVERNAME]]]-电子邮件验证
|
||||
嗨[[[USERNAME]]],[[[SERVERNAME]]]([[[SERVERURL]]])正在执行电子邮件验证。导航至以下链接以完成该过程:
|
||||
~
|
||||
~[[[SERVERURL]]]/checkmail?c=[[[COOKIE]]]
|
||||
~
|
||||
如果您没有发起此请求,请忽略此邮件。
|
19
emails/translations/account-invite_cs.html
Normal file
19
emails/translations/account-invite_cs.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Pozvánka na účet</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Pozvánka na účet</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Účet byl pro vás vytvořen na serveru <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, nyní k němu máte přístup:</p>
|
||||
<p>
|
||||
Uživatelské jméno: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
Heslo: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
S pozdravem,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_cs.txt
Normal file
5
emails/translations/account-invite_cs.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Pozvánka na účet
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
S pozdravem,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_de.html
Normal file
19
emails/translations/account-invite_de.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Kontoeinladung</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Kontoeinladung</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Auf dem Server wurde ein Konto für Sie erstellt <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>können Sie jetzt darauf zugreifen mit:</p>
|
||||
<p>
|
||||
Benutzername: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
Passwort: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Freundliche Grüße,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_de.txt
Normal file
5
emails/translations/account-invite_de.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Kontoeinladung
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
Freundliche Grüße,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_es.html
Normal file
19
emails/translations/account-invite_es.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Account Invitation</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account Invitation</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>An account was created for you on server <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, you can access it now with:</p>
|
||||
<p>
|
||||
Usuario: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
Contraseña: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Best regards,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_es.txt
Normal file
5
emails/translations/account-invite_es.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Account Invitation
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
Best regards,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_fr.html
Normal file
19
emails/translations/account-invite_fr.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Invitation au compte</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Invitation au compte</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Un compte a été créé pour vous sur le serveur <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, vous pouvez y accéder maintenant avec:</p>
|
||||
<p>
|
||||
Nom d'utilisateur: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
Mot de passe: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Meilleures salutations,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_fr.txt
Normal file
5
emails/translations/account-invite_fr.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Invitation au compte
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
Meilleures salutations,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_hi.html
Normal file
19
emails/translations/account-invite_hi.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Account Invitation</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account Invitation</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>An account was created for you on server <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, you can access it now with:</p>
|
||||
<p>
|
||||
उपयोगकर्ता नाम: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
कुंजिका: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Best regards,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_hi.txt
Normal file
5
emails/translations/account-invite_hi.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Account Invitation
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
Best regards,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_ja.html
Normal file
19
emails/translations/account-invite_ja.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]]-アカウントの招待</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]]-アカウントの招待</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>サーバー上にアカウントが作成されました <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>、あなたは今それを使ってそれにアクセスできます:</p>
|
||||
<p>
|
||||
ユーザー名: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
パスワード: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
宜しくお願いします、
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_ja.txt
Normal file
5
emails/translations/account-invite_ja.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]]-アカウントの招待
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
宜しくお願いします、
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_ko.html
Normal file
19
emails/translations/account-invite_ko.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Account Invitation</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account Invitation</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>An account was created for you on server <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, you can access it now with:</p>
|
||||
<p>
|
||||
사용자 이름: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
암호: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Best regards,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_ko.txt
Normal file
5
emails/translations/account-invite_ko.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Account Invitation
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
Best regards,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_nl.html
Normal file
19
emails/translations/account-invite_nl.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Account uitnodiging</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account uitnodiging</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Er is een account voor je aangemaakt op de server <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, je hebt er nu toegang toe met:</p>
|
||||
<p>
|
||||
Gebruikersnaam: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
Wachtwoord: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Vriendelijke groeten,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_nl.txt
Normal file
5
emails/translations/account-invite_nl.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Account uitnodiging
|
||||
Er is een account jouw aangemaakt op de server [[[SERVERNAME]]] ([[[SERVERURL]]]/), Je kan inloggen met de gebruikersnaam "[[[ACCOUNTNAME]]]" en wachtwoord "[[[PASSWORD]]]".
|
||||
~
|
||||
Vriendelijke groeten,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_pt.html
Normal file
19
emails/translations/account-invite_pt.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Account Invitation</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account Invitation</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>An account was created for you on server <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>, you can access it now with:</p>
|
||||
<p>
|
||||
Nome de usuário: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
Senha: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
Best regards,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_pt.txt
Normal file
5
emails/translations/account-invite_pt.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - Account Invitation
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
Best regards,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_ru.html
Normal file
19
emails/translations/account-invite_ru.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - приглашение в аккаунт</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - приглашение в аккаунт</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Учетная запись была создана для вас на сервере <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>Вы можете получить к нему доступ сейчас:</p>
|
||||
<p>
|
||||
Имя пользователя: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
Пароль: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
С уважением,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_ru.txt
Normal file
5
emails/translations/account-invite_ru.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]] - приглашение в аккаунт
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
С уважением,
|
||||
~[[[USERNAME]]]
|
19
emails/translations/account-invite_zh-chs.html
Normal file
19
emails/translations/account-invite_zh-chs.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]]-帐户邀请</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]]-帐户邀请</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>在服务器上为您创建了一个帐户 <a href="[[[SERVERURL]]]" notrans="1">[[[SERVERNAME]]]</a>,您现在可以通过以下方式访问它:</p>
|
||||
<p>
|
||||
用戶名: <b notrans="1">[[[ACCOUNTNAME]]]</b><br>
|
||||
密碼: <b notrans="1">[[[PASSWORD]]]</b>
|
||||
</p>
|
||||
最好的祝福,
|
||||
<br>
|
||||
[[[USERNAME]]]
|
||||
<br>
|
||||
</div></body></html>
|
5
emails/translations/account-invite_zh-chs.txt
Normal file
5
emails/translations/account-invite_zh-chs.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[[[SERVERNAME]]]-帐户邀请
|
||||
An account was created for you on server [[[SERVERNAME]]] ([[[SERVERURL]]]/), you can access it now with username "[[[ACCOUNTNAME]]]" and password "[[[PASSWORD]]]".
|
||||
~
|
||||
最好的祝福,
|
||||
~[[[USERNAME]]]
|
12
emails/translations/account-login_cs.html
Normal file
12
emails/translations/account-login_cs.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Přihlášení k účtu</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Přihlášení k účtu</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Váš přihlašovací token je: [[[TOKEN]]]</p>
|
||||
<p>Tento token lze použít pouze jednou a je platný po dobu 5 minut.</p>
|
||||
</div></body></html>
|
4
emails/translations/account-login_cs.txt
Normal file
4
emails/translations/account-login_cs.txt
Normal file
@ -0,0 +1,4 @@
|
||||
[[[SERVERNAME]]] - Přihlášení k účtu
|
||||
Váš přihlašovací token je: [[[TOKEN]]]
|
||||
~
|
||||
Tento token lze použít pouze jednou a je platný po dobu 5 minut.
|
12
emails/translations/account-login_de.html
Normal file
12
emails/translations/account-login_de.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Konto-Login</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Konto-Login</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Ihr Login-Token lautet: [[[TOKEN]]]</p>
|
||||
<p>Dieser Token kann nur einmal verwendet werden und ist 5 Minuten gültig.</p>
|
||||
</div></body></html>
|
4
emails/translations/account-login_de.txt
Normal file
4
emails/translations/account-login_de.txt
Normal file
@ -0,0 +1,4 @@
|
||||
[[[SERVERNAME]]] - Konto-Login
|
||||
Ihr Login-Token lautet: [[[TOKEN]]]
|
||||
~
|
||||
Dieser Token kann nur einmal verwendet werden und ist 5 Minuten gültig.
|
12
emails/translations/account-login_es.html
Normal file
12
emails/translations/account-login_es.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Account Login</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Account Login</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Your login token is: [[[TOKEN]]]</p>
|
||||
<p>This token can only be used once and is valid for 5 minutes.</p>
|
||||
</div></body></html>
|
4
emails/translations/account-login_es.txt
Normal file
4
emails/translations/account-login_es.txt
Normal file
@ -0,0 +1,4 @@
|
||||
[[[SERVERNAME]]] - Account Login
|
||||
Your login token is: [[[TOKEN]]]
|
||||
~
|
||||
This token can only be used once and is valid for 5 minutes.
|
12
emails/translations/account-login_fr.html
Normal file
12
emails/translations/account-login_fr.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html><head></head><body><div>[[[SERVERNAME]]] - Connexion au compte</div>
|
||||
<div style="font-family:Arial,Helvetica,sans-serif">
|
||||
<table style="background-color:#003366;color:lightgray;width:100%" cellpadding="8">
|
||||
<tbody><tr>
|
||||
<td>
|
||||
<b style="font-size:20px;font-family:Arial,Helvetica,sans-serif">[[[SERVERNAME]]] - Connexion au compte</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<p>Votre jeton de connexion est: [[[TOKEN]]]</p>
|
||||
<p>Ce jeton ne peut être utilisé qu'une seule fois et est valide pendant 5 minutes.</p>
|
||||
</div></body></html>
|
4
emails/translations/account-login_fr.txt
Normal file
4
emails/translations/account-login_fr.txt
Normal file
@ -0,0 +1,4 @@
|
||||
[[[SERVERNAME]]] - Connexion au compte
|
||||
Votre jeton de connexion est: [[[TOKEN]]]
|
||||
~
|
||||
Ce jeton ne peut être utilisé qu'une seule fois et est valide pendant 5 minutes.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user