mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-12-27 07:53:23 +03:00
Added Czech, MpsAliasHost.
This commit is contained in:
parent
18abb29d60
commit
d10758dcf2
4
agents/meshcore.min.js
vendored
4
agents/meshcore.min.js
vendored
@ -1211,7 +1211,6 @@ function createMeshCore(agent) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Remote desktop using native pipes
|
// Remote desktop using native pipes
|
||||||
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
|
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
|
||||||
this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
|
this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
|
||||||
@ -1231,6 +1230,9 @@ function createMeshCore(agent) {
|
|||||||
this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
|
this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Place wallpaper back if needed
|
||||||
|
// TODO
|
||||||
|
|
||||||
if (this.desktop.kvm.connectionCount == 0)
|
if (this.desktop.kvm.connectionCount == 0)
|
||||||
{
|
{
|
||||||
// Display a toast message. This may not be supported on all platforms.
|
// Display a toast message. This may not be supported on all platforms.
|
||||||
|
@ -18,9 +18,9 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
var obj = {};
|
var obj = {};
|
||||||
|
|
||||||
obj.parent = parent;
|
obj.parent = parent;
|
||||||
obj.fs = require("fs");
|
obj.fs = require('fs');
|
||||||
obj.forge = require("node-forge");
|
obj.forge = require('node-forge');
|
||||||
obj.crypto = require("crypto");
|
obj.crypto = require('crypto');
|
||||||
obj.tls = require('tls');
|
obj.tls = require('tls');
|
||||||
obj.pki = obj.forge.pki;
|
obj.pki = obj.forge.pki;
|
||||||
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } };
|
obj.dirExists = function (filePath) { try { return obj.fs.statSync(filePath).isDirectory(); } catch (err) { return false; } };
|
||||||
@ -47,7 +47,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
if (signkey == null) return { 'action': 'acmactivate', 'error': 2, 'errorText': 'No signing certificate found' }; // Did not find a match.
|
if (signkey == null) return { 'action': 'acmactivate', 'error': 2, 'errorText': 'No signing certificate found' }; // Did not find a match.
|
||||||
|
|
||||||
// If the matching certificate is a root cert, issue a leaf cert that matches the fqdn
|
// If the matching certificate is a root cert, issue a leaf cert that matches the fqdn
|
||||||
if (domain.amtacmactivation.certs[certIndex].cn == '*') return { 'action': 'acmactivate', 'error': 3, 'errorText': 'Unsupported activation' }; // TODO: Add support for this mode
|
if (domain.amtacmactivation.certs[certIndex].cn == '*') return { 'action': 'acmactivate', 'error': 3, 'errorText': "Unsupported activation" }; // TODO: Add support for this mode
|
||||||
|
|
||||||
// Setup both nonces, ready to be signed
|
// Setup both nonces, ready to be signed
|
||||||
const mcNonce = Buffer.from(obj.crypto.randomBytes(20), 'binary');
|
const mcNonce = Buffer.from(obj.crypto.randomBytes(20), 'binary');
|
||||||
@ -59,7 +59,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
var signer = obj.crypto.createSign(hashAlgo);
|
var signer = obj.crypto.createSign(hashAlgo);
|
||||||
signer.update(Buffer.concat([fwNonce, mcNonce]));
|
signer.update(Buffer.concat([fwNonce, mcNonce]));
|
||||||
signature = signer.sign(signkey, 'base64');
|
signature = signer.sign(signkey, 'base64');
|
||||||
} catch (ex) { return { 'action': 'acmactivate', 'error': 4, 'errorText': 'Unable to perform signature' }; }
|
} catch (ex) { return { 'action': 'acmactivate', 'error': 4, 'errorText': "Unable to perform signature" }; }
|
||||||
|
|
||||||
// Log the activation request, logging is a required step for activation.
|
// Log the activation request, logging is a required step for activation.
|
||||||
if (obj.logAmtActivation(domain, { time: new Date(), action: 'acmactivate', domain: domain.id, amtUuid: request.uuid, certHash: request.hash, hashType: hashAlgo, amtRealm: request.realm, amtFqdn: request.fqdn, user: user, password: pass, ipport: ipport, nodeid: nodeid, meshid: meshid, computerName: computerName, agentId: agentId, tag: request.tag, name: request.name }) == false) return { 'action': 'acmactivate', 'error': 5, 'errorText': 'Unable to log operation' };
|
if (obj.logAmtActivation(domain, { time: new Date(), action: 'acmactivate', domain: domain.id, amtUuid: request.uuid, certHash: request.hash, hashType: hashAlgo, amtRealm: request.realm, amtFqdn: request.fqdn, user: user, password: pass, ipport: ipport, nodeid: nodeid, meshid: meshid, computerName: computerName, agentId: agentId, tag: request.tag, name: request.name }) == false) return { 'action': 'acmactivate', 'error': 5, 'errorText': 'Unable to log operation' };
|
||||||
@ -240,7 +240,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
// Return the SHA384 hash of the certificate public key
|
// Return the SHA384 hash of the certificate public key
|
||||||
obj.getPublicKeyHash = function (cert) {
|
obj.getPublicKeyHash = function (cert) {
|
||||||
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
||||||
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: "hex", md: obj.forge.md.sha384.create() });
|
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: 'hex', md: obj.forge.md.sha384.create() });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the SHA384 hash of the certificate, return hex
|
// Return the SHA384 hash of the certificate, return hex
|
||||||
@ -254,7 +254,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
||||||
if ((x1 >= 0) && (x2 > x1)) {
|
if ((x1 >= 0) && (x2 > x1)) {
|
||||||
return obj.crypto.createHash('sha1').update(Buffer.from(cert.substring(x1 + 27, x2), 'base64')).digest('hex');
|
return obj.crypto.createHash('sha1').update(Buffer.from(cert.substring(x1 + 27, x2), 'base64')).digest('hex');
|
||||||
} else { console.log('ERROR: Unable to decode certificate.'); return null; }
|
} else { console.log("ERROR: Unable to decode certificate."); return null; }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -269,14 +269,14 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
||||||
if ((x1 >= 0) && (x2 > x1)) {
|
if ((x1 >= 0) && (x2 > x1)) {
|
||||||
return obj.crypto.createHash('sha384').update(Buffer.from(cert.substring(x1 + 27, x2), 'base64')).digest('hex');
|
return obj.crypto.createHash('sha384').update(Buffer.from(cert.substring(x1 + 27, x2), 'base64')).digest('hex');
|
||||||
} else { console.log('ERROR: Unable to decode certificate.'); return null; }
|
} else { console.log("ERROR: Unable to decode certificate."); return null; }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the SHA384 hash of the certificate public key
|
// Return the SHA384 hash of the certificate public key
|
||||||
obj.getPublicKeyHashBinary = function (cert) {
|
obj.getPublicKeyHashBinary = function (cert) {
|
||||||
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
||||||
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: "binary", md: obj.forge.md.sha384.create() });
|
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the SHA384 hash of the certificate, return binary
|
// Return the SHA384 hash of the certificate, return binary
|
||||||
@ -291,7 +291,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
var x1 = cert.indexOf('-----BEGIN CERTIFICATE-----'), x2 = cert.indexOf('-----END CERTIFICATE-----');
|
||||||
if ((x1 >= 0) && (x2 > x1)) {
|
if ((x1 >= 0) && (x2 > x1)) {
|
||||||
return obj.crypto.createHash('sha384').update(Buffer.from(cert.substring(x1 + 27, x2), 'base64')).digest('binary');
|
return obj.crypto.createHash('sha384').update(Buffer.from(cert.substring(x1 + 27, x2), 'base64')).digest('binary');
|
||||||
} else { console.log('ERROR: Unable to decode certificate.'); return null; }
|
} else { console.log("ERROR: Unable to decode certificate."); return null; }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -305,15 +305,15 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
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.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 = new Date();
|
||||||
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
|
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
|
||||||
if (addThumbPrintToName === true) { commonName += "-" + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: "hex" }).substring(0, 6); }
|
if (addThumbPrintToName === true) { commonName += '-' + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: 'hex' }).substring(0, 6); }
|
||||||
if (country == null) { country = "unknown"; }
|
if (country == null) { country = "unknown"; }
|
||||||
if (organization == null) { organization = "unknown"; }
|
if (organization == null) { organization = "unknown"; }
|
||||||
var attrs = [{ name: "commonName", value: commonName }, { name: "organizationName", value: organization }, { name: "countryName", value: country }];
|
var attrs = [{ name: 'commonName', value: commonName }, { name: 'organizationName', value: organization }, { name: 'countryName', value: country }];
|
||||||
cert.setSubject(attrs);
|
cert.setSubject(attrs);
|
||||||
cert.setIssuer(attrs);
|
cert.setIssuer(attrs);
|
||||||
// Create a root certificate
|
// Create a root certificate
|
||||||
//cert.setExtensions([{ name: "basicConstraints", cA: true }, { name: "nsCertType", sslCA: true, emailCA: true, objCA: true }, { name: "subjectKeyIdentifier" }]);
|
//cert.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'nsCertType', sslCA: true, emailCA: true, objCA: true }, { name: 'subjectKeyIdentifier' }]);
|
||||||
cert.setExtensions([{ name: "basicConstraints", cA: true }, { name: "subjectKeyIdentifier" }, { name: "keyUsage", keyCertSign: true }]);
|
cert.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'subjectKeyIdentifier' }, { name: 'keyUsage', keyCertSign: true }]);
|
||||||
cert.sign(keys.privateKey, obj.forge.md.sha384.create());
|
cert.sign(keys.privateKey, obj.forge.md.sha384.create());
|
||||||
|
|
||||||
return { cert: cert, key: keys.privateKey };
|
return { cert: cert, key: keys.privateKey };
|
||||||
@ -329,16 +329,16 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
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.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 = new Date();
|
||||||
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
|
cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
|
||||||
if (addThumbPrintToName === true) { commonName += "-" + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: "hex" }).substring(0, 6); }
|
if (addThumbPrintToName === true) { commonName += "-" + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: 'hex' }).substring(0, 6); }
|
||||||
var attrs = [{ name: "commonName", value: commonName }];
|
var attrs = [{ name: 'commonName', value: commonName }];
|
||||||
if (country != null) { attrs.push({ name: "countryName", value: country }); }
|
if (country != null) { attrs.push({ name: 'countryName', value: country }); }
|
||||||
if (organization != null) { attrs.push({ name: "organizationName", value: organization }); }
|
if (organization != null) { attrs.push({ name: 'organizationName', value: organization }); }
|
||||||
cert.setSubject(attrs);
|
cert.setSubject(attrs);
|
||||||
cert.setIssuer(rootcert.cert.subject.attributes);
|
cert.setIssuer(rootcert.cert.subject.attributes);
|
||||||
|
|
||||||
if (extKeyUsage == null) { extKeyUsage = { name: "extKeyUsage", serverAuth: true }; } else { extKeyUsage.name = "extKeyUsage"; }
|
if (extKeyUsage == null) { extKeyUsage = { name: 'extKeyUsage', serverAuth: true }; } else { extKeyUsage.name = 'extKeyUsage'; }
|
||||||
//var extensions = [{ name: "basicConstraints", cA: false }, { name: "keyUsage", keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true }, extKeyUsage, { name: "nsCertType", client: false, server: true, email: false, objsign: false, sslCA: false, emailCA: false, objCA: false }, { name: "subjectKeyIdentifier" }];
|
//var extensions = [{ name: 'basicConstraints', cA: false }, { name: 'keyUsage', keyCertSign: true, digitalSignature: true, nonRepudiation: true, keyEncipherment: true, dataEncipherment: true }, extKeyUsage, { name: "nsCertType", client: false, server: true, email: false, objsign: false, sslCA: false, emailCA: false, objCA: false }, { name: "subjectKeyIdentifier" }];
|
||||||
var extensions = [{ name: "basicConstraints", cA: false }, { name: "keyUsage", keyCertSign: false, digitalSignature: true, nonRepudiation: false, keyEncipherment: true, dataEncipherment: (extKeyUsage.serverAuth !== true) }, extKeyUsage, { name: "subjectKeyIdentifier" }];
|
var extensions = [{ name: 'basicConstraints', cA: false }, { name: 'keyUsage', keyCertSign: false, digitalSignature: true, nonRepudiation: false, keyEncipherment: true, dataEncipherment: (extKeyUsage.serverAuth !== true) }, extKeyUsage, { name: "subjectKeyIdentifier" }];
|
||||||
|
|
||||||
if (extKeyUsage.serverAuth === true) {
|
if (extKeyUsage.serverAuth === true) {
|
||||||
// Set subjectAltName according to commonName parsing.
|
// Set subjectAltName according to commonName parsing.
|
||||||
@ -355,14 +355,14 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
// set only DNS when commonName is a FQDN
|
// set only DNS when commonName is a FQDN
|
||||||
altNames.push({ type: 2, value: commonName });
|
altNames.push({ type: 2, value: commonName });
|
||||||
}
|
}
|
||||||
altNames.push({ type: 6, value: "http://" + commonName + "/" })
|
altNames.push({ type: 6, value: 'http://' + commonName + '/' })
|
||||||
|
|
||||||
// Add localhost stuff for easy testing on localhost ;)
|
// Add localhost stuff for easy testing on localhost ;)
|
||||||
altNames.push({ type: 2, value: "localhost" });
|
altNames.push({ type: 2, value: 'localhost' });
|
||||||
altNames.push({ type: 6, value: "http://localhost/" });
|
altNames.push({ type: 6, value: 'http://localhost/' });
|
||||||
altNames.push({ type: 7, ip: "127.0.0.1" });
|
altNames.push({ type: 7, ip: '127.0.0.1' });
|
||||||
|
|
||||||
extensions.push({ name: "subjectAltName", altNames: altNames });
|
extensions.push({ name: 'subjectAltName', altNames: altNames });
|
||||||
}
|
}
|
||||||
|
|
||||||
cert.setExtensions(extensions);
|
cert.setExtensions(extensions);
|
||||||
@ -413,69 +413,69 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
var rcount = 0;
|
var rcount = 0;
|
||||||
|
|
||||||
// If the root certificate already exist, load it
|
// If the root certificate already exist, load it
|
||||||
if (obj.fileExists("root-cert-public.crt") && obj.fileExists("root-cert-private.key")) {
|
if (obj.fileExists('root-cert-public.crt') && obj.fileExists('root-cert-private.key')) {
|
||||||
var rootCertificate = obj.fileLoad("root-cert-public.crt", "utf8");
|
var rootCertificate = obj.fileLoad('root-cert-public.crt', 'utf8');
|
||||||
var rootPrivateKey = obj.fileLoad("root-cert-private.key", "utf8");
|
var rootPrivateKey = obj.fileLoad('root-cert-private.key', 'utf8');
|
||||||
r.root = { cert: rootCertificate, key: rootPrivateKey };
|
r.root = { cert: rootCertificate, key: rootPrivateKey };
|
||||||
rcount++;
|
rcount++;
|
||||||
|
|
||||||
// Check if the root certificate has the "Certificate Signing (04)" Key usage.
|
// Check if the root certificate has the "Certificate Signing (04)" Key usage.
|
||||||
// This option is required for newer versions of Intel AMT for CIRA/WS-EVENTS.
|
// This option is required for newer versions of Intel AMT for CIRA/WS-EVENTS.
|
||||||
var xroot = obj.pki.certificateFromPem(rootCertificate);
|
var xroot = obj.pki.certificateFromPem(rootCertificate);
|
||||||
var xext = xroot.getExtension("keyUsage");
|
var xext = xroot.getExtension('keyUsage');
|
||||||
if ((xext == null) || (xext.keyCertSign !== true)) {
|
if ((xext == null) || (xext.keyCertSign !== true)) {
|
||||||
// We need to fix this certificate
|
// We need to fix this certificate
|
||||||
console.log('Fixing root certificate to add signing key usage...');
|
console.log("Fixing root certificate to add signing key usage...");
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-public-backup.crt"), rootCertificate);
|
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-public-backup.crt'), rootCertificate);
|
||||||
xroot.setExtensions([{ name: "basicConstraints", cA: true }, { name: "subjectKeyIdentifier" }, { name: "keyUsage", keyCertSign: true }]);
|
xroot.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'subjectKeyIdentifier' }, { name: 'keyUsage', keyCertSign: true }]);
|
||||||
var xrootPrivateKey = obj.pki.privateKeyFromPem(rootPrivateKey);
|
var xrootPrivateKey = obj.pki.privateKeyFromPem(rootPrivateKey);
|
||||||
xroot.sign(xrootPrivateKey, obj.forge.md.sha384.create());
|
xroot.sign(xrootPrivateKey, obj.forge.md.sha384.create());
|
||||||
r.root.cert = obj.pki.certificateToPem(xroot);
|
r.root.cert = obj.pki.certificateToPem(xroot);
|
||||||
try { obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-public.crt"), r.root.cert); } catch (ex) { }
|
try { obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-public.crt'), r.root.cert); } catch (ex) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.tlsoffload) {
|
if (args.tlsoffload) {
|
||||||
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
|
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
|
||||||
if (obj.fileExists("webserver-cert-public.crt")) {
|
if (obj.fileExists('webserver-cert-public.crt')) {
|
||||||
r.web = { cert: obj.fileLoad("webserver-cert-public.crt", "utf8") };
|
r.web = { cert: obj.fileLoad('webserver-cert-public.crt', 'utf8') };
|
||||||
rcount++;
|
rcount++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the web certificate already exist, load it. Load both certificate and private key
|
// If the web certificate already exist, load it. Load both certificate and private key
|
||||||
if (obj.fileExists("webserver-cert-public.crt") && obj.fileExists("webserver-cert-private.key")) {
|
if (obj.fileExists('webserver-cert-public.crt') && obj.fileExists('webserver-cert-private.key')) {
|
||||||
r.web = { cert: obj.fileLoad("webserver-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-cert-private.key", "utf8") };
|
r.web = { cert: obj.fileLoad('webserver-cert-public.crt', 'utf8'), key: obj.fileLoad('webserver-cert-private.key', 'utf8') };
|
||||||
rcount++;
|
rcount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the mps certificate already exist, load it
|
// If the mps certificate already exist, load it
|
||||||
if (obj.fileExists("mpsserver-cert-public.crt") && obj.fileExists("mpsserver-cert-private.key")) {
|
if (obj.fileExists('mpsserver-cert-public.crt') && obj.fileExists('mpsserver-cert-private.key')) {
|
||||||
r.mps = { cert: obj.fileLoad("mpsserver-cert-public.crt", "utf8"), key: obj.fileLoad("mpsserver-cert-private.key", "utf8") };
|
r.mps = { cert: obj.fileLoad('mpsserver-cert-public.crt', 'utf8'), key: obj.fileLoad('mpsserver-cert-private.key', 'utf8') };
|
||||||
rcount++;
|
rcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the agent certificate already exist, load it
|
// If the agent certificate already exist, load it
|
||||||
if (obj.fileExists("agentserver-cert-public.crt") && obj.fileExists("agentserver-cert-private.key")) {
|
if (obj.fileExists("agentserver-cert-public.crt") && obj.fileExists("agentserver-cert-private.key")) {
|
||||||
r.agent = { cert: obj.fileLoad("agentserver-cert-public.crt", "utf8"), key: obj.fileLoad("agentserver-cert-private.key", "utf8") };
|
r.agent = { cert: obj.fileLoad("agentserver-cert-public.crt", 'utf8'), key: obj.fileLoad("agentserver-cert-private.key", 'utf8') };
|
||||||
rcount++;
|
rcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the swarm server certificate exist, load it (This is an optional certificate)
|
// If the swarm server certificate exist, load it (This is an optional certificate)
|
||||||
if (obj.fileExists("swarmserver-cert-public.crt") && obj.fileExists("swarmserver-cert-private.key")) {
|
if (obj.fileExists('swarmserver-cert-public.crt') && obj.fileExists('swarmserver-cert-private.key')) {
|
||||||
r.swarmserver = { cert: obj.fileLoad("swarmserver-cert-public.crt", "utf8"), key: obj.fileLoad("swarmserver-cert-private.key", "utf8") };
|
r.swarmserver = { cert: obj.fileLoad('swarmserver-cert-public.crt', 'utf8'), key: obj.fileLoad('swarmserver-cert-private.key', 'utf8') };
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the swarm server root certificate exist, load it (This is an optional certificate)
|
// If the swarm server root certificate exist, load it (This is an optional certificate)
|
||||||
if (obj.fileExists("swarmserverroot-cert-public.crt")) {
|
if (obj.fileExists('swarmserverroot-cert-public.crt')) {
|
||||||
r.swarmserverroot = { cert: obj.fileLoad("swarmserverroot-cert-public.crt", "utf8") };
|
r.swarmserverroot = { cert: obj.fileLoad('swarmserverroot-cert-public.crt', 'utf8') };
|
||||||
}
|
}
|
||||||
|
|
||||||
// If CA certificates are present, load them
|
// If CA certificates are present, load them
|
||||||
do {
|
do {
|
||||||
caok = false;
|
caok = false;
|
||||||
if (obj.fileExists("webserver-cert-chain" + caindex + ".crt")) {
|
if (obj.fileExists('webserver-cert-chain' + caindex + '.crt')) {
|
||||||
calist.push(obj.fileLoad("webserver-cert-chain" + caindex + ".crt", "utf8"));
|
calist.push(obj.fileLoad('webserver-cert-chain' + caindex + '.crt', 'utf8'));
|
||||||
caok = true;
|
caok = true;
|
||||||
}
|
}
|
||||||
caindex++;
|
caindex++;
|
||||||
@ -483,24 +483,24 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
if (r.web != null) { r.web.ca = calist; }
|
if (r.web != null) { r.web.ca = calist; }
|
||||||
|
|
||||||
// Decode certificate arguments
|
// Decode certificate arguments
|
||||||
var commonName = "un-configured";
|
var commonName = 'un-configured';
|
||||||
var country = null;
|
var country = null;
|
||||||
var organization = null;
|
var organization = null;
|
||||||
var forceWebCertGen = 0;
|
var forceWebCertGen = 0;
|
||||||
var forceMpsCertGen = 0;
|
var forceMpsCertGen = 0;
|
||||||
if (certargs != undefined) {
|
if (certargs != undefined) {
|
||||||
var xargs = certargs.split(",");
|
var xargs = certargs.split(',');
|
||||||
if (xargs.length > 0) { commonName = xargs[0]; }
|
if (xargs.length > 0) { commonName = xargs[0]; }
|
||||||
if (xargs.length > 1) { country = xargs[1]; }
|
if (xargs.length > 1) { country = xargs[1]; }
|
||||||
if (xargs.length > 2) { organization = xargs[2]; }
|
if (xargs.length > 2) { organization = xargs[2]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode MPS certificate arguments, this is for the Intel AMT CIRA server
|
// Decode MPS certificate arguments, this is for the Intel AMT CIRA server
|
||||||
var mpsCommonName = commonName;
|
var mpsCommonName = ((config.settings != null) && (typeof config.settings.mpsaliashost == 'string')) ? config.settings.mpsaliashost : commonName;
|
||||||
var mpsCountry = country;
|
var mpsCountry = country;
|
||||||
var mpsOrganization = organization;
|
var mpsOrganization = organization;
|
||||||
if (mpscertargs !== undefined) {
|
if (mpscertargs !== undefined) {
|
||||||
var xxargs = mpscertargs.split(",");
|
var xxargs = mpscertargs.split(',');
|
||||||
if (xxargs.length > 0) { mpsCommonName = xxargs[0]; }
|
if (xxargs.length > 0) { mpsCommonName = xxargs[0]; }
|
||||||
if (xxargs.length > 1) { mpsCountry = xxargs[1]; }
|
if (xxargs.length > 1) { mpsCountry = xxargs[1]; }
|
||||||
if (xxargs.length > 2) { mpsOrganization = xxargs[2]; }
|
if (xxargs.length > 2) { mpsOrganization = xxargs[2]; }
|
||||||
@ -508,16 +508,16 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
|
|
||||||
if (rcount === rcountmax) {
|
if (rcount === rcountmax) {
|
||||||
// Fetch the certificates names for the main certificate
|
// Fetch the certificates names for the main certificate
|
||||||
r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField("CN").value;
|
r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField('CN').value;
|
||||||
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
||||||
r.WebIssuer = webCertificate.issuer.getField("CN").value;
|
r.WebIssuer = webCertificate.issuer.getField('CN').value;
|
||||||
if (commonName == "un-configured") { // If the "cert" name is not set, try to use the certificate CN instead (ok if the certificate is not wildcard).
|
if (commonName == 'un-configured') { // If the "cert" name is not set, try to use the certificate CN instead (ok if the certificate is not wildcard).
|
||||||
commonName = webCertificate.subject.getField("CN").value;
|
commonName = webCertificate.subject.getField('CN').value;
|
||||||
if (commonName.startsWith('*.')) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
if (commonName.startsWith('*.')) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
||||||
}
|
}
|
||||||
r.CommonName = commonName;
|
r.CommonName = commonName;
|
||||||
r.CommonNames = [commonName.toLowerCase()];
|
r.CommonNames = [commonName.toLowerCase()];
|
||||||
var altNames = webCertificate.getExtension("subjectAltName");
|
var altNames = webCertificate.getExtension('subjectAltName');
|
||||||
if (altNames) {
|
if (altNames) {
|
||||||
for (i = 0; i < altNames.altNames.length; i++) {
|
for (i = 0; i < altNames.altNames.length; i++) {
|
||||||
var acn = altNames.altNames[i].value.toLowerCase();
|
var acn = altNames.altNames[i].value.toLowerCase();
|
||||||
@ -525,7 +525,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
|
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
|
||||||
r.RootName = rootCertificate.subject.getField("CN").value;
|
r.RootName = rootCertificate.subject.getField('CN').value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for domains that have DNS names and load their certificates
|
// Look for domains that have DNS names and load their certificates
|
||||||
@ -535,28 +535,28 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
dnsname = config.domains[i].dns;
|
dnsname = config.domains[i].dns;
|
||||||
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
|
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
|
||||||
if (obj.compareCertificateNames(r.CommonNames, dnsname) == true) {
|
if (obj.compareCertificateNames(r.CommonNames, dnsname) == true) {
|
||||||
r.dns[i] = { cert: obj.fileLoad("webserver-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-cert-private.key", "utf8") };
|
r.dns[i] = { cert: obj.fileLoad('webserver-cert-public.crt', 'utf8'), key: obj.fileLoad('webserver-cert-private.key', 'utf8') };
|
||||||
} else {
|
} else {
|
||||||
if (args.tlsoffload) {
|
if (args.tlsoffload) {
|
||||||
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
|
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
|
||||||
if (obj.fileExists("webserver-" + i + "-cert-public.crt")) {
|
if (obj.fileExists('webserver-' + i + '-cert-public.crt')) {
|
||||||
r.dns[i] = { cert: obj.fileLoad("webserver-" + i + "-cert-public.crt", "utf8") };
|
r.dns[i] = { cert: obj.fileLoad('webserver-' + i + '-cert-public.crt', 'utf8') };
|
||||||
config.domains[i].certs = r.dns[i];
|
config.domains[i].certs = r.dns[i];
|
||||||
} else {
|
} else {
|
||||||
console.log("WARNING: File \"webserver-" + i + "-cert-public.crt\" missing, domain \"" + i + "\" will not work correctly.");
|
console.log("WARNING: File \"webserver-" + i + "-cert-public.crt\" missing, domain \"" + i + "\" will not work correctly.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the web certificate already exist, load it. Load both certificate and private key
|
// If the web certificate already exist, load it. Load both certificate and private key
|
||||||
if (obj.fileExists("webserver-" + i + "-cert-public.crt") && obj.fileExists("webserver-" + i + "-cert-private.key")) {
|
if (obj.fileExists('webserver-' + i + '-cert-public.crt') && obj.fileExists('webserver-' + i + '-cert-private.key')) {
|
||||||
r.dns[i] = { cert: obj.fileLoad("webserver-" + i + "-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-" + i + "-cert-private.key", "utf8") };
|
r.dns[i] = { cert: obj.fileLoad('webserver-' + i + '-cert-public.crt', 'utf8'), key: obj.fileLoad('webserver-' + i + '-cert-private.key', 'utf8') };
|
||||||
config.domains[i].certs = r.dns[i];
|
config.domains[i].certs = r.dns[i];
|
||||||
// If CA certificates are present, load them
|
// If CA certificates are present, load them
|
||||||
caindex = 1;
|
caindex = 1;
|
||||||
r.dns[i].ca = [];
|
r.dns[i].ca = [];
|
||||||
do {
|
do {
|
||||||
caok = false;
|
caok = false;
|
||||||
if (obj.fileExists("webserver-" + i + "-cert-chain" + caindex + ".crt")) {
|
if (obj.fileExists('webserver-' + i + '-cert-chain' + caindex + '.crt')) {
|
||||||
r.dns[i].ca.push(obj.fileLoad("webserver-" + i + "-cert-chain" + caindex + ".crt", "utf8"));
|
r.dns[i].ca.push(obj.fileLoad('webserver-' + i + '-cert-chain' + caindex + '.crt', 'utf8'));
|
||||||
caok = true;
|
caok = true;
|
||||||
}
|
}
|
||||||
caindex++;
|
caindex++;
|
||||||
@ -571,9 +571,9 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
|
|
||||||
if (rcount === rcountmax) {
|
if (rcount === rcountmax) {
|
||||||
if ((certargs == null) && (mpscertargs == null)) { if (func != undefined) { func(r); } return r; } // If no certificate arguments are given, keep the certificate
|
if ((certargs == null) && (mpscertargs == null)) { if (func != undefined) { func(r); } return r; } // If no certificate arguments are given, keep the certificate
|
||||||
var xcountry, xcountryField = webCertificate.subject.getField("C");
|
var xcountry, xcountryField = webCertificate.subject.getField('C');
|
||||||
if (xcountryField != null) { xcountry = xcountryField.value; }
|
if (xcountryField != null) { xcountry = xcountryField.value; }
|
||||||
var xorganization, xorganizationField = webCertificate.subject.getField("O");
|
var xorganization, xorganizationField = webCertificate.subject.getField('O');
|
||||||
if (xorganizationField != null) { xorganization = xorganizationField.value; }
|
if (xorganizationField != null) { xorganization = xorganizationField.value; }
|
||||||
if (certargs == null) { commonName = r.CommonName; country = xcountry; organization = xorganization; }
|
if (certargs == null) { commonName = r.CommonName; country = xcountry; organization = xorganization; }
|
||||||
|
|
||||||
@ -590,15 +590,15 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
if (parent.configurationFiles != null) { console.log("Error: Vault/Database missing some certificates."); process.exit(0); return null; }
|
if (parent.configurationFiles != null) { console.log("Error: Vault/Database missing some certificates."); process.exit(0); return null; }
|
||||||
|
|
||||||
console.log("Generating certificates, may take a few minutes...");
|
console.log("Generating certificates, may take a few minutes...");
|
||||||
parent.updateServerState("state", "generatingcertificates");
|
parent.updateServerState('state', 'generatingcertificates');
|
||||||
|
|
||||||
// If a certificate is missing, but web certificate is present and --cert is not used, set the names to be the same as the web certificate
|
// If a certificate is missing, but web certificate is present and --cert is not used, set the names to be the same as the web certificate
|
||||||
if ((certargs == null) && (r.web != null)) {
|
if ((certargs == null) && (r.web != null)) {
|
||||||
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
||||||
commonName = webCertificate.subject.getField("CN").value;
|
commonName = webCertificate.subject.getField('CN').value;
|
||||||
var xcountryField = webCertificate.subject.getField("C");
|
var xcountryField = webCertificate.subject.getField('C');
|
||||||
if (xcountryField != null) { country = xcountryField.value; }
|
if (xcountryField != null) { country = xcountryField.value; }
|
||||||
var xorganizationField = webCertificate.subject.getField("O");
|
var xorganizationField = webCertificate.subject.getField('O');
|
||||||
if (xorganizationField != null) { organization = xorganizationField.value; }
|
if (xorganizationField != null) { organization = xorganizationField.value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,18 +606,18 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
if (r.root == null) {
|
if (r.root == null) {
|
||||||
// If the root certificate does not exist, create one
|
// If the root certificate does not exist, create one
|
||||||
console.log("Generating root certificate...");
|
console.log("Generating root certificate...");
|
||||||
rootCertAndKey = obj.GenerateRootCertificate(true, "MeshCentralRoot", null, null, strongCertificate);
|
rootCertAndKey = obj.GenerateRootCertificate(true, 'MeshCentralRoot', null, null, strongCertificate);
|
||||||
rootCertificate = obj.pki.certificateToPem(rootCertAndKey.cert);
|
rootCertificate = obj.pki.certificateToPem(rootCertAndKey.cert);
|
||||||
rootPrivateKey = obj.pki.privateKeyToPem(rootCertAndKey.key);
|
rootPrivateKey = obj.pki.privateKeyToPem(rootCertAndKey.key);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-public.crt"), rootCertificate);
|
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-public.crt'), rootCertificate);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("root-cert-private.key"), rootPrivateKey);
|
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-private.key'), rootPrivateKey);
|
||||||
} else {
|
} else {
|
||||||
// Keep the root certificate we have
|
// Keep the root certificate we have
|
||||||
rootCertAndKey = { cert: obj.pki.certificateFromPem(r.root.cert), key: obj.pki.privateKeyFromPem(r.root.key) };
|
rootCertAndKey = { cert: obj.pki.certificateFromPem(r.root.cert), key: obj.pki.privateKeyFromPem(r.root.key) };
|
||||||
rootCertificate = r.root.cert;
|
rootCertificate = r.root.cert;
|
||||||
rootPrivateKey = r.root.key;
|
rootPrivateKey = r.root.key;
|
||||||
}
|
}
|
||||||
var rootName = rootCertAndKey.cert.subject.getField("CN").value;
|
var rootName = rootCertAndKey.cert.subject.getField('CN').value;
|
||||||
|
|
||||||
// If the web certificate does not exist, create one
|
// If the web certificate does not exist, create one
|
||||||
var webCertAndKey, webCertificate, webPrivateKey;
|
var webCertAndKey, webCertificate, webPrivateKey;
|
||||||
@ -626,8 +626,8 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
webCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, commonName, country, organization, null, strongCertificate);
|
webCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, commonName, country, organization, null, strongCertificate);
|
||||||
webCertificate = obj.pki.certificateToPem(webCertAndKey.cert);
|
webCertificate = obj.pki.certificateToPem(webCertAndKey.cert);
|
||||||
webPrivateKey = obj.pki.privateKeyToPem(webCertAndKey.key);
|
webPrivateKey = obj.pki.privateKeyToPem(webCertAndKey.key);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-cert-public.crt"), webCertificate);
|
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-cert-public.crt'), webCertificate);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-cert-private.key"), webPrivateKey);
|
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-cert-private.key'), webPrivateKey);
|
||||||
} else {
|
} else {
|
||||||
// Keep the console certificate we have
|
// Keep the console certificate we have
|
||||||
if (args.tlsoffload) {
|
if (args.tlsoffload) {
|
||||||
@ -639,17 +639,17 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
webPrivateKey = r.web.key;
|
webPrivateKey = r.web.key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var webIssuer = webCertAndKey.cert.issuer.getField("CN").value;
|
var webIssuer = webCertAndKey.cert.issuer.getField('CN').value;
|
||||||
|
|
||||||
// If the mesh agent server certificate does not exist, create one
|
// If the mesh agent server certificate does not exist, create one
|
||||||
var agentCertAndKey, agentCertificate, agentPrivateKey;
|
var agentCertAndKey, agentCertificate, agentPrivateKey;
|
||||||
if (r.agent == null) {
|
if (r.agent == null) {
|
||||||
console.log("Generating MeshAgent certificate...");
|
console.log("Generating MeshAgent certificate...");
|
||||||
agentCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, true, "MeshCentralAgentServer", country, organization, { }, strongCertificate);
|
agentCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, true, 'MeshCentralAgentServer', country, organization, { }, strongCertificate);
|
||||||
agentCertificate = obj.pki.certificateToPem(agentCertAndKey.cert);
|
agentCertificate = obj.pki.certificateToPem(agentCertAndKey.cert);
|
||||||
agentPrivateKey = obj.pki.privateKeyToPem(agentCertAndKey.key);
|
agentPrivateKey = obj.pki.privateKeyToPem(agentCertAndKey.key);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("agentserver-cert-public.crt"), agentCertificate);
|
obj.fs.writeFileSync(parent.getConfigFilePath('agentserver-cert-public.crt'), agentCertificate);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("agentserver-cert-private.key"), agentPrivateKey);
|
obj.fs.writeFileSync(parent.getConfigFilePath('agentserver-cert-private.key'), agentPrivateKey);
|
||||||
} else {
|
} else {
|
||||||
// Keep the mesh agent server certificate we have
|
// Keep the mesh agent server certificate we have
|
||||||
agentCertAndKey = { cert: obj.pki.certificateFromPem(r.agent.cert), key: obj.pki.privateKeyFromPem(r.agent.key) };
|
agentCertAndKey = { cert: obj.pki.certificateFromPem(r.agent.cert), key: obj.pki.privateKeyFromPem(r.agent.key) };
|
||||||
@ -664,8 +664,8 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
mpsCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, mpsCommonName, mpsCountry, mpsOrganization, null, false);
|
mpsCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, mpsCommonName, mpsCountry, mpsOrganization, null, false);
|
||||||
mpsCertificate = obj.pki.certificateToPem(mpsCertAndKey.cert);
|
mpsCertificate = obj.pki.certificateToPem(mpsCertAndKey.cert);
|
||||||
mpsPrivateKey = obj.pki.privateKeyToPem(mpsCertAndKey.key);
|
mpsPrivateKey = obj.pki.privateKeyToPem(mpsCertAndKey.key);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("mpsserver-cert-public.crt"), mpsCertificate);
|
obj.fs.writeFileSync(parent.getConfigFilePath('mpsserver-cert-public.crt'), mpsCertificate);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("mpsserver-cert-private.key"), mpsPrivateKey);
|
obj.fs.writeFileSync(parent.getConfigFilePath('mpsserver-cert-private.key'), mpsPrivateKey);
|
||||||
} else {
|
} else {
|
||||||
// Keep the console certificate we have
|
// Keep the console certificate we have
|
||||||
mpsCertAndKey = { cert: obj.pki.certificateFromPem(r.mps.cert), key: obj.pki.privateKeyFromPem(r.mps.key) };
|
mpsCertAndKey = { cert: obj.pki.certificateFromPem(r.mps.cert), key: obj.pki.privateKeyFromPem(r.mps.key) };
|
||||||
@ -677,18 +677,18 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
|
|
||||||
// Fetch the certificates names for the main certificate
|
// Fetch the certificates names for the main certificate
|
||||||
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
||||||
r.WebIssuer = webCertificate.issuer.getField("CN").value;
|
r.WebIssuer = webCertificate.issuer.getField('CN').value;
|
||||||
r.CommonName = webCertificate.subject.getField("CN").value;
|
r.CommonName = webCertificate.subject.getField('CN').value;
|
||||||
if (r.CommonName.startsWith('*.')) {
|
if (r.CommonName.startsWith('*.')) {
|
||||||
if (commonName.indexOf('.') == -1) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
if (commonName.indexOf('.') == -1) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
||||||
if (commonName.startsWith('*.')) { console.log("ERROR: Server can't use a wildcard name: " + commonName); process.exit(0); return; }
|
if (commonName.startsWith('*.')) { console.log("ERROR: Server can't use a wildcard name: " + commonName); process.exit(0); return; }
|
||||||
r.CommonName = commonName;
|
r.CommonName = commonName;
|
||||||
}
|
}
|
||||||
r.CommonNames = [r.CommonName.toLowerCase()];
|
r.CommonNames = [r.CommonName.toLowerCase()];
|
||||||
var altNames = webCertificate.getExtension("subjectAltName");
|
var altNames = webCertificate.getExtension('subjectAltName');
|
||||||
if (altNames) { for (i = 0; i < altNames.altNames.length; i++) { r.CommonNames.push(altNames.altNames[i].value.toLowerCase()); } }
|
if (altNames) { for (i = 0; i < altNames.altNames.length; i++) { r.CommonNames.push(altNames.altNames[i].value.toLowerCase()); } }
|
||||||
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
|
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
|
||||||
r.RootName = rootCertificate.subject.getField("CN").value;
|
r.RootName = rootCertificate.subject.getField('CN').value;
|
||||||
|
|
||||||
// Look for domains with DNS names that have no certificates and generated them.
|
// Look for domains with DNS names that have no certificates and generated them.
|
||||||
for (i in config.domains) {
|
for (i in config.domains) {
|
||||||
@ -696,17 +696,17 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
dnsname = config.domains[i].dns;
|
dnsname = config.domains[i].dns;
|
||||||
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
|
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
|
||||||
if (obj.compareCertificateNames(r.CommonNames, dnsname) == true) {
|
if (obj.compareCertificateNames(r.CommonNames, dnsname) == true) {
|
||||||
r.dns[i] = { cert: obj.fileLoad("webserver-cert-public.crt", "utf8"), key: obj.fileLoad("webserver-cert-private.key", "utf8") };
|
r.dns[i] = { cert: obj.fileLoad('webserver-cert-public.crt', 'utf8'), key: obj.fileLoad('webserver-cert-private.key', 'utf8') };
|
||||||
} else {
|
} else {
|
||||||
if (!args.tlsoffload) {
|
if (!args.tlsoffload) {
|
||||||
// If the web certificate does not exist, create it
|
// If the web certificate does not exist, create it
|
||||||
if ((obj.fileExists("webserver-" + i + "-cert-public.crt") === false) || (obj.fileExists("webserver-" + i + "-cert-private.key") === false)) {
|
if ((obj.fileExists('webserver-' + i + '-cert-public.crt') === false) || (obj.fileExists('webserver-' + i + '-cert-private.key') === false)) {
|
||||||
console.log("Generating HTTPS certificate for " + i + "...");
|
console.log('Generating HTTPS certificate for ' + i + '...');
|
||||||
var xwebCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, dnsname, country, organization, null, strongCertificate);
|
var xwebCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, dnsname, country, organization, null, strongCertificate);
|
||||||
var xwebCertificate = obj.pki.certificateToPem(xwebCertAndKey.cert);
|
var xwebCertificate = obj.pki.certificateToPem(xwebCertAndKey.cert);
|
||||||
var xwebPrivateKey = obj.pki.privateKeyToPem(xwebCertAndKey.key);
|
var xwebPrivateKey = obj.pki.privateKeyToPem(xwebCertAndKey.key);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-public.crt"), xwebCertificate);
|
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt'), xwebCertificate);
|
||||||
obj.fs.writeFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-private.key"), xwebPrivateKey);
|
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-private.key'), xwebPrivateKey);
|
||||||
r.dns[i] = { cert: xwebCertificate, key: xwebPrivateKey };
|
r.dns[i] = { cert: xwebCertificate, key: xwebPrivateKey };
|
||||||
config.domains[i].certs = r.dns[i];
|
config.domains[i].certs = r.dns[i];
|
||||||
|
|
||||||
@ -715,8 +715,8 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
r.dns[i].ca = [];
|
r.dns[i].ca = [];
|
||||||
do {
|
do {
|
||||||
caok = false;
|
caok = false;
|
||||||
if (obj.fileExists("webserver-" + i + "-cert-chain" + caindex + ".crt")) {
|
if (obj.fileExists('webserver-' + i + '-cert-chain' + caindex + '.crt')) {
|
||||||
r.dns[i].ca.push(fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("webserver-" + i + "-cert-chain" + caindex + ".crt"), "utf8")));
|
r.dns[i].ca.push(fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-chain' + caindex + '.crt'), 'utf8')));
|
||||||
caok = true;
|
caok = true;
|
||||||
}
|
}
|
||||||
caindex++;
|
caindex++;
|
||||||
@ -728,13 +728,13 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the swarm server certificate exist, load it (This is an optional certificate)
|
// If the swarm server certificate exist, load it (This is an optional certificate)
|
||||||
if (obj.fileExists("swarmserver-cert-public.crt") && obj.fileExists("swarmserver-cert-private.key")) {
|
if (obj.fileExists('swarmserver-cert-public.crt') && obj.fileExists('swarmserver-cert-private.key')) {
|
||||||
r.swarmserver = { cert: fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("swarmserver-cert-public.crt"), "utf8")), key: fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("swarmserver-cert-private.key"), "utf8")) };
|
r.swarmserver = { cert: fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath('swarmserver-cert-public.crt'), 'utf8')), key: fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("swarmserver-cert-private.key"), 'utf8')) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the swarm server root certificate exist, load it (This is an optional certificate)
|
// If the swarm server root certificate exist, load it (This is an optional certificate)
|
||||||
if (obj.fileExists("swarmserverroot-cert-public.crt")) {
|
if (obj.fileExists('swarmserverroot-cert-public.crt')) {
|
||||||
r.swarmserverroot = { cert: fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("swarmserverroot-cert-public.crt"), "utf8")) };
|
r.swarmserverroot = { cert: fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath('swarmserverroot-cert-public.crt'), 'utf8')) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// If CA certificates are present, load them
|
// If CA certificates are present, load them
|
||||||
@ -743,8 +743,8 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
r.web.ca = [];
|
r.web.ca = [];
|
||||||
do {
|
do {
|
||||||
caok = false;
|
caok = false;
|
||||||
if (obj.fileExists("webserver-cert-chain" + caindex + ".crt")) {
|
if (obj.fileExists('webserver-cert-chain' + caindex + '.crt')) {
|
||||||
r.web.ca.push(fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath("webserver-cert-chain" + caindex + ".crt"), "utf8")));
|
r.web.ca.push(fixEndOfLines(obj.fs.readFileSync(parent.getConfigFilePath('webserver-cert-chain' + caindex + '.crt'), 'utf8')));
|
||||||
caok = true;
|
caok = true;
|
||||||
}
|
}
|
||||||
caindex++;
|
caindex++;
|
||||||
@ -756,9 +756,9 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Accelerators, used to dispatch work to other processes
|
// Accelerators, used to dispatch work to other processes
|
||||||
const fork = require("child_process").fork;
|
const fork = require('child_process').fork;
|
||||||
const program = require("path").join(__dirname, "meshaccelerator.js");
|
const program = require('path').join(__dirname, 'meshaccelerator.js');
|
||||||
const acceleratorTotalCount = require("os").cpus().length; // TODO: Check if this accelerator can scale.
|
const acceleratorTotalCount = require('os').cpus().length; // TODO: Check if this accelerator can scale.
|
||||||
var acceleratorCreateCount = acceleratorTotalCount;
|
var acceleratorCreateCount = acceleratorTotalCount;
|
||||||
var freeAccelerators = [];
|
var freeAccelerators = [];
|
||||||
var pendingAccelerator = [];
|
var pendingAccelerator = [];
|
||||||
@ -803,21 +803,21 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
if (freeAccelerators.length > 0) { return freeAccelerators.pop(); }
|
if (freeAccelerators.length > 0) { return freeAccelerators.pop(); }
|
||||||
if (acceleratorCreateCount > 0) {
|
if (acceleratorCreateCount > 0) {
|
||||||
acceleratorCreateCount--;
|
acceleratorCreateCount--;
|
||||||
var accelerator = fork(program, [], { stdio: ["pipe", "pipe", "pipe", "ipc"] });
|
var accelerator = fork(program, [], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] });
|
||||||
accelerator.accid = acceleratorCreateCount;
|
accelerator.accid = acceleratorCreateCount;
|
||||||
accelerator.on("message", function (message) {
|
accelerator.on('message', function (message) {
|
||||||
acceleratorMessage++;
|
acceleratorMessage++;
|
||||||
this.x.func(this.x.tag, message);
|
this.x.func(this.x.tag, message);
|
||||||
delete this.x;
|
delete this.x;
|
||||||
if (pendingAccelerator.length > 0) { this.send(this.x = pendingAccelerator.shift()); } else { freeAccelerators.push(this); }
|
if (pendingAccelerator.length > 0) { this.send(this.x = pendingAccelerator.shift()); } else { freeAccelerators.push(this); }
|
||||||
});
|
});
|
||||||
accelerator.on("exit", function (code) {
|
accelerator.on('exit', function (code) {
|
||||||
if (this.x) { pendingAccelerator.push(this.x); delete this.x; }
|
if (this.x) { pendingAccelerator.push(this.x); delete this.x; }
|
||||||
acceleratorCreateCount++;
|
acceleratorCreateCount++;
|
||||||
if (pendingAccelerator.length > 0) { var acc = obj.getAccelerator(); acc.send(acc.x = pendingAccelerator.shift()); }
|
if (pendingAccelerator.length > 0) { var acc = obj.getAccelerator(); acc.send(acc.x = pendingAccelerator.shift()); }
|
||||||
});
|
});
|
||||||
accelerator.on("error", function (code) { }); // Not sure if somethign should be done here to help kill the process.
|
accelerator.on('error', function (code) { }); // Not sure if somethign should be done here to help kill the process.
|
||||||
accelerator.send({ action: "setState", certs: obj.acceleratorCertStore });
|
accelerator.send({ action: 'setState', certs: obj.acceleratorCertStore });
|
||||||
return accelerator;
|
return accelerator;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -836,20 +836,20 @@ module.exports.CertificateOperations = function (parent) {
|
|||||||
acceleratorPerformSignatureFuncCall++;
|
acceleratorPerformSignatureFuncCall++;
|
||||||
if (acceleratorTotalCount <= 1) {
|
if (acceleratorTotalCount <= 1) {
|
||||||
// No accelerators available
|
// No accelerators available
|
||||||
if (typeof privatekey == "number") { privatekey = obj.acceleratorCertStore[privatekey].key; }
|
if (typeof privatekey == 'number') { privatekey = obj.acceleratorCertStore[privatekey].key; }
|
||||||
const sign = obj.crypto.createSign("SHA384");
|
const sign = obj.crypto.createSign('SHA384');
|
||||||
sign.end(Buffer.from(data, "binary"));
|
sign.end(Buffer.from(data, 'binary'));
|
||||||
try { func(tag, sign.sign(privatekey).toString("binary")); } catch (ex) { acceleratorMessageException++; acceleratorMessageLastException = ex; }
|
try { func(tag, sign.sign(privatekey).toString('binary')); } catch (ex) { acceleratorMessageException++; acceleratorMessageLastException = ex; }
|
||||||
} else {
|
} else {
|
||||||
var acc = obj.getAccelerator();
|
var acc = obj.getAccelerator();
|
||||||
if (acc == null) {
|
if (acc == null) {
|
||||||
// Add to pending accelerator workload
|
// Add to pending accelerator workload
|
||||||
acceleratorPerformSignaturePushFuncCall++;
|
acceleratorPerformSignaturePushFuncCall++;
|
||||||
pendingAccelerator.push({ action: "sign", key: privatekey, data: data, tag: tag, func: func });
|
pendingAccelerator.push({ action: 'sign', key: privatekey, data: data, tag: tag, func: func });
|
||||||
} else {
|
} else {
|
||||||
// Send to accelerator now
|
// Send to accelerator now
|
||||||
acceleratorPerformSignatureRunFuncCall++;
|
acceleratorPerformSignatureRunFuncCall++;
|
||||||
acc.send(acc.x = { action: "sign", key: privatekey, data: data, tag: tag, func: func });
|
acc.send(acc.x = { action: 'sign', key: privatekey, data: data, tag: tag, func: func });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -650,9 +650,9 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
|
|
||||||
// Lower case all keys in the config file
|
// Lower case all keys in the config file
|
||||||
try {
|
try {
|
||||||
require('./common.js').objKeysToLower(config2, ["ldapoptions"]);
|
require('./common.js').objKeysToLower(config2, ['ldapoptions']);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
console.log('CRITICAL ERROR: Unable to access the file \"./common.js\".\r\nCheck folder & file permissions.');
|
console.log("CRITICAL ERROR: Unable to access the file \"./common.js\".\r\nCheck folder & file permissions.");
|
||||||
process.exit();
|
process.exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -719,6 +719,7 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
var bannedDomains = ['public', 'private', 'images', 'scripts', 'styles', 'views']; // List of banned domains
|
var bannedDomains = ['public', 'private', 'images', 'scripts', 'styles', 'views']; // List of banned domains
|
||||||
for (i in obj.config.domains) { for (var j in bannedDomains) { if (i == bannedDomains[j]) { console.log("ERROR: Domain '" + i + "' is not allowed domain name in config.json."); return; } } }
|
for (i in obj.config.domains) { for (var j in bannedDomains) { if (i == bannedDomains[j]) { console.log("ERROR: Domain '" + i + "' is not allowed domain name in config.json."); return; } } }
|
||||||
for (i in obj.config.domains) {
|
for (i in obj.config.domains) {
|
||||||
|
if ((i.length > 0) && (i[0] == '_')) { delete obj.config.domains[i]; continue; } // Remove any domains with names that start with _
|
||||||
if (typeof config.domains[i].auth == 'string') { config.domains[i].auth = config.domains[i].auth.toLowerCase(); }
|
if (typeof config.domains[i].auth == 'string') { config.domains[i].auth = config.domains[i].auth.toLowerCase(); }
|
||||||
if (obj.config.domains[i].limits == null) { obj.config.domains[i].limits = {}; }
|
if (obj.config.domains[i].limits == null) { obj.config.domains[i].limits = {}; }
|
||||||
if (obj.config.domains[i].dns == null) { obj.config.domains[i].url = (i == '') ? '/' : ('/' + i + '/'); } else { obj.config.domains[i].url = '/'; }
|
if (obj.config.domains[i].dns == null) { obj.config.domains[i].url = (i == '') ? '/' : ('/' + i + '/'); } else { obj.config.domains[i].url = '/'; }
|
||||||
@ -789,7 +790,7 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
|
if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
|
||||||
user[0].siteadmin = 4294967295; // 0xFFFFFFFF
|
user[0].siteadmin = 4294967295; // 0xFFFFFFFF
|
||||||
obj.db.Set(user[0], function () {
|
obj.db.Set(user[0], function () {
|
||||||
if (user[0].domain == '') { console.log('User ' + user[0].name + ' set to site administrator.'); } else { console.log('User ' + user[0].name + ' of domain ' + user[0].domain + ' set to site administrator.'); }
|
if (user[0].domain == '') { console.log('User ' + user[0].name + ' set to site administrator.'); } else { console.log("User " + user[0].name + " of domain " + user[0].domain + " set to site administrator."); }
|
||||||
process.exit();
|
process.exit();
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
@ -807,7 +808,7 @@ function CreateMeshCentralServer(config, args) {
|
|||||||
if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
|
if (user.length != 1) { console.log("Invalid user name."); process.exit(); return; }
|
||||||
if (user[0].siteadmin) { delete user[0].siteadmin; }
|
if (user[0].siteadmin) { delete user[0].siteadmin; }
|
||||||
obj.db.Set(user[0], function () {
|
obj.db.Set(user[0], function () {
|
||||||
if (user[0].domain == '') { console.log('User ' + user[0].name + ' is not a site administrator.'); } else { console.log('User ' + user[0].name + ' of domain ' + user[0].domain + ' is not a site administrator.'); }
|
if (user[0].domain == '') { console.log("User " + user[0].name + " is not a site administrator."); } else { console.log("User " + user[0].name + " of domain " + user[0].domain + " is not a site administrator."); }
|
||||||
process.exit();
|
process.exit();
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
1234
public/commander.htm
1234
public/commander.htm
File diff suppressed because one or more lines are too long
@ -49,6 +49,12 @@ var CreateAmtRemoteTerminal = function (divid, options) {
|
|||||||
var _scrollRegion;
|
var _scrollRegion;
|
||||||
var _altKeypadMode = false;
|
var _altKeypadMode = false;
|
||||||
var scrollBackBuffer = [];
|
var scrollBackBuffer = [];
|
||||||
|
// ###BEGIN###{Terminal-Enumation-UTF8}
|
||||||
|
//var utf8decodeBuffer = '';
|
||||||
|
// ###END###{Terminal-Enumation-UTF8}
|
||||||
|
// ###BEGIN###{Terminal-Enumation-All}
|
||||||
|
var utf8decodeBuffer = '';
|
||||||
|
// ###END###{Terminal-Enumation-All}
|
||||||
obj.title = null;
|
obj.title = null;
|
||||||
obj.onTitleChange = null;
|
obj.onTitleChange = null;
|
||||||
|
|
||||||
@ -73,10 +79,12 @@ var CreateAmtRemoteTerminal = function (divid, options) {
|
|||||||
obj.ProcessData = function (str) {
|
obj.ProcessData = function (str) {
|
||||||
if (obj.debugmode == 2) { console.log("TRecv(" + str.length + "): " + rstr2hex(str)); }
|
if (obj.debugmode == 2) { console.log("TRecv(" + str.length + "): " + rstr2hex(str)); }
|
||||||
// ###BEGIN###{Terminal-Enumation-UTF8}
|
// ###BEGIN###{Terminal-Enumation-UTF8}
|
||||||
//str = decode_utf8(str);
|
//try { str = decode_utf8(utf8decodeBuffer + str); } catch (ex) { utf8decodeBuffer += str; return; } // If we get data in the middle of a UTF-8 code, buffer it for next time.
|
||||||
|
//utf8decodeBuffer = '';
|
||||||
// ###END###{Terminal-Enumation-UTF8}
|
// ###END###{Terminal-Enumation-UTF8}
|
||||||
// ###BEGIN###{Terminal-Enumation-All}
|
// ###BEGIN###{Terminal-Enumation-All}
|
||||||
if (obj.terminalEmulation == 0) { str = decode_utf8(str); }
|
if (obj.terminalEmulation == 0) { try { str = decode_utf8(utf8decodeBuffer + str); } catch (ex) { utf8decodeBuffer += str; return; } } // If we get data in the middle of a UTF-8 code, buffer it for next time.
|
||||||
|
utf8decodeBuffer = '';
|
||||||
// ###END###{Terminal-Enumation-All}
|
// ###END###{Terminal-Enumation-All}
|
||||||
if (obj.capture != null) obj.capture += str; _ProcessVt100EscString(str); obj.TermDraw();
|
if (obj.capture != null) obj.capture += str; _ProcessVt100EscString(str); obj.TermDraw();
|
||||||
}
|
}
|
||||||
@ -604,6 +612,12 @@ var CreateAmtRemoteTerminal = function (divid, options) {
|
|||||||
_scrollRegion = [0, (obj.height - 1)];
|
_scrollRegion = [0, (obj.height - 1)];
|
||||||
_altKeypadMode = false;
|
_altKeypadMode = false;
|
||||||
obj.TermClear(7 << 6);
|
obj.TermClear(7 << 6);
|
||||||
|
// ###BEGIN###{Terminal-Enumation-UTF8}
|
||||||
|
//utf8decodeBuffer = '';
|
||||||
|
// ###END###{Terminal-Enumation-UTF8}
|
||||||
|
// ###BEGIN###{Terminal-Enumation-All}
|
||||||
|
utf8decodeBuffer = '';
|
||||||
|
// ###END###{Terminal-Enumation-All}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _EraseCursorToEol() {
|
function _EraseCursorToEol() {
|
||||||
|
1
public/translations/player-min_cs.htm
Normal file
1
public/translations/player-min_cs.htm
Normal file
File diff suppressed because one or more lines are too long
537
public/translations/player_cs.htm
Normal file
537
public/translations/player_cs.htm
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/agent-desktop-0.0.2.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/amt-terminal-0.0.2.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/zlib.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/zlib-inflate.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/zlib-adler32.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/zlib-crc32.js"></script>
|
||||||
|
</head>
|
||||||
|
<body style="overflow:hidden;background-color:black">
|
||||||
|
<div id="p11" class="noselect" style="overflow:hidden">
|
||||||
|
<div id="deskarea0">
|
||||||
|
<div id="deskarea1" class="areaHead">
|
||||||
|
<div class="toright2">
|
||||||
|
<div class="deskareaicon" title="Toggle View Mode" onclick="toggleAspectRatio(1)">⇲</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input id="OpenFileButton" type="button" value="Otevřít soubor..." onclick="openfile()">
|
||||||
|
<span id="deskstatus"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="deskarea2" style="">
|
||||||
|
<div class="areaProgress"><div id="progressbar" style=""></div></div>
|
||||||
|
</div>
|
||||||
|
<div id="deskarea3x" style="max-height:calc(100vh - 54px);height:calc(100vh - 54px);" onclick="togglePause()">
|
||||||
|
<div id="bigok" style="display:none;left:calc((100vh / 2))"><b>✓</b></div>
|
||||||
|
<div id="bigfail" style="display:none;left:calc((100vh / 2))"><b>✗</b></div>
|
||||||
|
<div id="metadatadiv" style="padding:20px;color:lightgrey;text-align:left;display:none"></div>
|
||||||
|
<div id="DeskParent">
|
||||||
|
<canvas id="Desk" width="640" height="480"></canvas>
|
||||||
|
</div>
|
||||||
|
<div id="TermParent" style="display:none">
|
||||||
|
<pre id="Term"></pre>
|
||||||
|
</div>
|
||||||
|
<div id="p11DeskConsoleMsg" style="display:none;cursor:pointer;position:absolute;left:30px;top:17px;color:yellow;background-color:rgba(0,0,0,0.6);padding:10px;border-radius:5px" onclick="clearConsoleMsg()"></div>
|
||||||
|
</div>
|
||||||
|
<div id="deskarea4" class="areaFoot">
|
||||||
|
<div class="toright2">
|
||||||
|
<div id="timespan" style="padding-top:4px;padding-right:4px">00:00:00</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<input id="PlayButton" type="button" value="Play" disabled="disabled" onclick="play()">
|
||||||
|
<input id="PauseButton" type="button" value="Pause" disabled="disabled" onclick="pause()">
|
||||||
|
<input id="RestartButton" type="button" value="Restart" disabled="disabled" onclick="restart()">
|
||||||
|
<select id="PlaySpeed" onchange="this.blur();">
|
||||||
|
<option value="4">1/4 Speed</option>
|
||||||
|
<option value="2">1/2 Speed</option>
|
||||||
|
<option value="1" selected="">Normalní rychlost</option>
|
||||||
|
<option value="0.5">2x rychlost</option>
|
||||||
|
<option value="0.25">4x Speed</option>
|
||||||
|
<option value="0.1">10x Speed</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="dialog" class="noselect" style="display:none">
|
||||||
|
<div id="dialogHeader">
|
||||||
|
<div tabindex="0" id="id_dialogclose" onclick="setDialogMode()" onkeypress="if (event.key == 'Enter') setDialogMode()">✖</div>
|
||||||
|
<div id="id_dialogtitle"></div>
|
||||||
|
</div>
|
||||||
|
<div id="dialogBody">
|
||||||
|
<div id="dialog1">
|
||||||
|
<div id="id_dialogMessage" style=""></div>
|
||||||
|
</div>
|
||||||
|
<div id="dialog2" style="">
|
||||||
|
<div id="id_dialogOptions"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="idx_dlgButtonBar">
|
||||||
|
<input id="idx_dlgCancelButton" type="button" value="Zrušit" style="" onclick="dialogclose(0)">
|
||||||
|
<input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
|
||||||
|
<div><input id="idx_dlgDeleteButton" type="button" value="Smazat" style="display:none" onclick="dialogclose(2)"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var recFile = null;
|
||||||
|
var recFilePtr = 0;
|
||||||
|
var recFileStartTime = 0;
|
||||||
|
var recFileLastTime = 0;
|
||||||
|
var recFileEndTime = 0;
|
||||||
|
var recFileMetadata = null;
|
||||||
|
var recFileProtocol = 0;
|
||||||
|
var agentDesktop = null;
|
||||||
|
var amtDesktop = null;
|
||||||
|
var playing = false;
|
||||||
|
var readState = 0;
|
||||||
|
var waitTimer = null;
|
||||||
|
var waitTimerArgs = null;
|
||||||
|
var deskAspectRatio = 0;
|
||||||
|
var currentDeltaTimeTotalSec = 0;
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
window.onresize = deskAdjust;
|
||||||
|
document.ondrop = ondrop;
|
||||||
|
document.ondragover = ondragover;
|
||||||
|
document.ondragleave = ondragleave;
|
||||||
|
document.onkeypress = onkeypress;
|
||||||
|
Q('PlaySpeed').value = 1;
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readNextBlock(func) {
|
||||||
|
if ((recFilePtr + 16) > recFile.size) { QS('progressbar').width = '100%'; func(-1); } else {
|
||||||
|
var fr = new FileReader();
|
||||||
|
fr.onload = function () {
|
||||||
|
var type = ReadShort(this.result, 0);
|
||||||
|
var flags = ReadShort(this.result, 2);
|
||||||
|
var size = ReadInt(this.result, 4);
|
||||||
|
var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
|
||||||
|
if ((recFilePtr + 16 + size) > recFile.size) { QS('progressbar').width = '100%'; func(-1); } else {
|
||||||
|
var fr2 = new FileReader();
|
||||||
|
fr2.onload = function () {
|
||||||
|
recFilePtr += (16 + size);
|
||||||
|
if (recFileEndTime == 0) {
|
||||||
|
// File pointer progress bar
|
||||||
|
QS('progressbar').width = Math.floor(100 * (recFilePtr / recFile.size)) + '%';
|
||||||
|
} else {
|
||||||
|
// Time progress bar
|
||||||
|
QS('progressbar').width = Math.floor(((recFileLastTime - recFileStartTime) / (recFileEndTime - recFileStartTime)) * 100) + '%';
|
||||||
|
}
|
||||||
|
func(type, flags, time, this.result);
|
||||||
|
};
|
||||||
|
fr2.readAsBinaryString(recFile.slice(recFilePtr + 16, recFilePtr + 16 + size));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fr.readAsBinaryString(recFile.slice(recFilePtr, recFilePtr + 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readLastBlock(func) {
|
||||||
|
if (recFile.size < 32) { func(-1); } else {
|
||||||
|
var fr = new FileReader();
|
||||||
|
fr.onload = function () {
|
||||||
|
var type = ReadShort(this.result, 0);
|
||||||
|
var flags = ReadShort(this.result, 2);
|
||||||
|
var size = ReadInt(this.result, 4);
|
||||||
|
var time = (ReadInt(this.result, 8) << 32) + ReadInt(this.result, 12);
|
||||||
|
if ((type == 3) && (size == 16) && (this.result.substring(16, 32) == 'MeshCentralMCREC')) { func(type, flags, time); } else { func(-1); }
|
||||||
|
};
|
||||||
|
fr.readAsBinaryString(recFile.slice(recFile.size - 32, recFile.size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addInfo(name, value) { if (value == null) return ''; return addInfoNoEsc(name, EscapeHtml(value)); }
|
||||||
|
|
||||||
|
function addInfoNoEsc(name, value) {
|
||||||
|
if (value == null) return '';
|
||||||
|
return '<span style=color:gray>' + EscapeHtml(name) + '</span>: <span style=font-size:20px>' + value + '</span><br/>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function processFirstBlock(type, flags, time, data) {
|
||||||
|
recFileProtocol = 0;
|
||||||
|
if ((type != 1) || (flags != 0)) { cleanup(); return; }
|
||||||
|
try { recFileMetadata = JSON.parse(data) } catch (ex) { cleanup(); return; }
|
||||||
|
if ((recFileMetadata == null) || (recFileMetadata.magic != 'MeshCentralRelaySession') || (recFileMetadata.ver != 1)) { cleanup(); return; }
|
||||||
|
var x = '';
|
||||||
|
x += addInfo("Time", recFileMetadata.time);
|
||||||
|
if (recFileEndTime != 0) { var secs = Math.floor((recFileEndTime - time) / 1000); x += addInfo("Duration", format("{0} second{1}", secs, (secs > 1) ? 's' : '')); }
|
||||||
|
x += addInfo("Uživatel", recFileMetadata.username);
|
||||||
|
x += addInfo("UserID", recFileMetadata.userid);
|
||||||
|
x += addInfo("SessionID", recFileMetadata.sessionid);
|
||||||
|
if (recFileMetadata.ipaddr1 && recFileMetadata.ipaddr2) { x += addInfo("Addresses", format("{0} to {1}", recFileMetadata.ipaddr1, recFileMetadata.ipaddr2)); }
|
||||||
|
if (recFileMetadata.devicename) { x += addInfo("DeviceName", recFileMetadata.devicename); }
|
||||||
|
x += addInfo("NodeID", recFileMetadata.nodeid);
|
||||||
|
if (recFileMetadata.protocol) {
|
||||||
|
var p = recFileMetadata.protocol;
|
||||||
|
if (p == 1) { p = "MeshCentral Terminal"; }
|
||||||
|
else if (p == 2) { p = "MeshCentral Desktop"; }
|
||||||
|
else if (p == 100) { p = "Intel® AMT WSMAN"; }
|
||||||
|
else if (p == 101) { p = "Intel® AMT Redirection"; }
|
||||||
|
x += addInfoNoEsc("Protokol", p);
|
||||||
|
}
|
||||||
|
QV('DeskParent', true);
|
||||||
|
QV('TermParent', false);
|
||||||
|
if (recFileMetadata.protocol == 1) {
|
||||||
|
// MeshCentral remote terminal
|
||||||
|
recFileProtocol = 1;
|
||||||
|
x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
|
||||||
|
QE('PlayButton', true);
|
||||||
|
QE('PauseButton', false);
|
||||||
|
QE('RestartButton', false);
|
||||||
|
recFileStartTime = recFileLastTime = time;
|
||||||
|
}
|
||||||
|
else if (recFileMetadata.protocol == 2) {
|
||||||
|
// MeshCentral remote desktop
|
||||||
|
recFileProtocol = 2;
|
||||||
|
x += '<br /><br /><span style=color:gray>' + "Press [space] to play/pause." + '</span>';
|
||||||
|
QE('PlayButton', true);
|
||||||
|
QE('PauseButton', false);
|
||||||
|
QE('RestartButton', false);
|
||||||
|
recFileStartTime = recFileLastTime = time;
|
||||||
|
agentDesktop = CreateAgentRemoteDesktop('Desk');
|
||||||
|
agentDesktop.onScreenSizeChange = deskAdjust;
|
||||||
|
agentDesktop.State = 3;
|
||||||
|
deskAdjust();
|
||||||
|
}
|
||||||
|
else if (recFileMetadata.protocol == 101) {
|
||||||
|
// Intel AMT Redirection
|
||||||
|
recFileProtocol = 101;
|
||||||
|
x += '<br /><br /><span style=color:gray>Press [space] to play/pause.</span>';
|
||||||
|
QE('PlayButton', true);
|
||||||
|
QE('PauseButton', false);
|
||||||
|
QE('RestartButton', false);
|
||||||
|
recFileStartTime = recFileLastTime = time;
|
||||||
|
amtDesktop = CreateAmtRemoteDesktop('Desk');
|
||||||
|
amtDesktop.onScreenSizeChange = deskAdjust;
|
||||||
|
amtDesktop.State = 3;
|
||||||
|
amtDesktop.Start();
|
||||||
|
deskAdjust();
|
||||||
|
}
|
||||||
|
QV('metadatadiv', true);
|
||||||
|
QH('metadatadiv', x);
|
||||||
|
QH('deskstatus', recFile.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processBlock(type, flags, time, data) {
|
||||||
|
if (type < 0) { pause(); return; }
|
||||||
|
var waitTime = Math.round((time - recFileLastTime) * parseFloat(Q('PlaySpeed').value));
|
||||||
|
if (waitTime < 5) {
|
||||||
|
processBlockEx(type, flags, time, data);
|
||||||
|
} else {
|
||||||
|
waitTimerArgs = [type, flags, time, data]
|
||||||
|
waitTimer = setTimeout(function () { waitTimer = null; processBlockEx(waitTimerArgs[0], waitTimerArgs[1], waitTimerArgs[2], waitTimerArgs[3]); }, waitTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processBlockEx(type, flags, time, data) {
|
||||||
|
if (playing == false) return;
|
||||||
|
var flagBinary = (flags & 1) != 0, flagUser = (flags & 2) != 0;
|
||||||
|
|
||||||
|
// Update the clock
|
||||||
|
var deltaTimeTotalSec = Math.floor((time - recFileStartTime) / 1000);
|
||||||
|
if (currentDeltaTimeTotalSec != deltaTimeTotalSec) {
|
||||||
|
currentDeltaTimeTotalSec = deltaTimeTotalSec;
|
||||||
|
var deltaTimeHours = Math.floor(deltaTimeTotalSec / 3600);
|
||||||
|
deltaTimeTotalSec -= (deltaTimeHours * 3600)
|
||||||
|
var deltaTimeMinutes = Math.floor(deltaTimeTotalSec / 60);
|
||||||
|
deltaTimeTotalSec -= (deltaTimeHours * 60)
|
||||||
|
var deltaTimeSeconds = Math.floor(deltaTimeTotalSec);
|
||||||
|
QH('timespan', pad2(deltaTimeHours) + ':' + pad2(deltaTimeMinutes) + ':' + pad2(deltaTimeSeconds))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((type == 2) && flagBinary && !flagUser) {
|
||||||
|
// Device --> User data
|
||||||
|
if (recFileProtocol == 1) {
|
||||||
|
// MeshCentral Terminal
|
||||||
|
agentTerminal.ProcessData(data);
|
||||||
|
} else if (recFileProtocol == 2) {
|
||||||
|
// MeshCentral Remote Desktop
|
||||||
|
agentDesktop.ProcessData(data);
|
||||||
|
} else if (recFileProtocol == 101) {
|
||||||
|
// Intel AMT KVM
|
||||||
|
if ((readState == 0) && (rstr2hex(data) == '4100000000000000')) {
|
||||||
|
// We are not authenticated, KVM data starts here.
|
||||||
|
readState = 1;
|
||||||
|
if (data.length > 8) { amtDesktop.ProcessData(data.substring(8)); }
|
||||||
|
} else if (readState == 1) {
|
||||||
|
amtDesktop.ProcessData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((type == 2) && flagBinary && flagUser) {
|
||||||
|
// User --> Device data
|
||||||
|
if (recFileProtocol == 101) {
|
||||||
|
// Intel AMT KVM
|
||||||
|
if (rstr2hex(data) == '0000000008080001000700070003050200000000') { amtDesktop.bpp = 1; } // Switch to 1 byte per pixel.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recFileLastTime = time;
|
||||||
|
if (playing) { readNextBlock(processBlock); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
recFile = null;
|
||||||
|
recFilePtr = 0;
|
||||||
|
recFileMetadata = null;
|
||||||
|
playing = false;
|
||||||
|
if (agentDesktop != null) { agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height); agentDesktop = null; }
|
||||||
|
if (amtDesktop != null) { amtDesktop.canvas.clearRect(0, 0, amtDesktop.CanvasId.width, amtDesktop.CanvasId.height); amtDesktop = null; }
|
||||||
|
readState = 0;
|
||||||
|
waitTimerArgs = null;
|
||||||
|
currentDeltaTimeTotalSec = 0;
|
||||||
|
recFileEndTime = 0;
|
||||||
|
agentTerminal = null;
|
||||||
|
if (waitTimer != null) { clearTimeout(waitTimer); waitTimer = null; }
|
||||||
|
QH('deskstatus', '');
|
||||||
|
QE('PlayButton', false);
|
||||||
|
QE('PauseButton', false);
|
||||||
|
QE('RestartButton', false);
|
||||||
|
QS('progressbar').width = '0px';
|
||||||
|
QH('timespan', '00:00:00');
|
||||||
|
QV('metadatadiv', true);
|
||||||
|
QH('metadatadiv', '<span style=\"font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:28px\">MeshCentral Session Player</span><br /><br /><span style=color:gray>' + "Drag & drop a .mcrec file or click \"Open File...\"" + '</span>');
|
||||||
|
QV('DeskParent', true);
|
||||||
|
QV('TermParent', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ondrop(e) {
|
||||||
|
haltEvent(e);
|
||||||
|
QV('bigfail', false);
|
||||||
|
QV('bigok', false);
|
||||||
|
|
||||||
|
// Check if these are files we can upload, remove all folders.
|
||||||
|
if (e.dataTransfer == null) return;
|
||||||
|
var files = [];
|
||||||
|
for (var i in e.dataTransfer.files) {
|
||||||
|
if ((e.dataTransfer.files[i].type != null) && (e.dataTransfer.files[i].size != null) && (e.dataTransfer.files[i].size != 0) && (e.dataTransfer.files[i].name.endsWith('.mcrec'))) {
|
||||||
|
files.push(e.dataTransfer.files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (files.length == 0) return;
|
||||||
|
cleanup();
|
||||||
|
recFile = files[0];
|
||||||
|
recFilePtr = 0;
|
||||||
|
readNextBlock(processFirstBlock);
|
||||||
|
readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
|
||||||
|
}
|
||||||
|
|
||||||
|
var dragtimer = null;
|
||||||
|
function ondragover(e) {
|
||||||
|
haltEvent(e);
|
||||||
|
if (dragtimer != null) { clearTimeout(dragtimer); dragtimer = null; }
|
||||||
|
var ac = true;
|
||||||
|
QV('bigok', ac);
|
||||||
|
QV('bigfail', !ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ondragleave(e) {
|
||||||
|
haltEvent(e);
|
||||||
|
dragtimer = setTimeout(function () { QV('bigfail', false); QV('bigok', false); dragtimer = null; }, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onkeypress(e) {
|
||||||
|
if (xxdialogMode) return;
|
||||||
|
if (e.key == ' ') { togglePause(); haltEvent(e); }
|
||||||
|
if (e.key == '1') { Q('PlaySpeed').value = 4; haltEvent(e); }
|
||||||
|
if (e.key == '2') { Q('PlaySpeed').value = 2; haltEvent(e); }
|
||||||
|
if (e.key == '3') { Q('PlaySpeed').value = 1; haltEvent(e); }
|
||||||
|
if (e.key == '4') { Q('PlaySpeed').value = 0.5; haltEvent(e); }
|
||||||
|
if (e.key == '5') { Q('PlaySpeed').value = 0.25; haltEvent(e); }
|
||||||
|
if (e.key == '6') { Q('PlaySpeed').value = 0.1; haltEvent(e); }
|
||||||
|
if (e.key == '0') { pause(); restart(); haltEvent(e); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function openfile() {
|
||||||
|
var x = '<input type=file name=files id=p2fileinput style=width:100% accept=".mcrec" onchange="openfileChanged()" />';
|
||||||
|
setDialogMode(2, "Otevřít soubor...", 3, openfileEx, x);
|
||||||
|
QE('idx_dlgOkButton', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openfileEx() {
|
||||||
|
var xfiles = Q('p2fileinput').files;
|
||||||
|
if (xfiles != null) { var files = []; for (var i in xfiles) { if ((xfiles[i].type != null) && (xfiles[i].size != null) && (xfiles[i].size != 0) && (xfiles[i].name.endsWith('.mcrec'))) { files.push(xfiles[i]); } } }
|
||||||
|
if (files.length == 0) return;
|
||||||
|
cleanup();
|
||||||
|
recFile = files[0];
|
||||||
|
recFilePtr = 0;
|
||||||
|
readNextBlock(processFirstBlock);
|
||||||
|
readLastBlock(function (type, flags, time) { if (type == 3) { recFileEndTime = time; } else { recFileEndTime = 0; } });
|
||||||
|
Q('OpenFileButton').blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openfileChanged() {
|
||||||
|
var xfiles = Q('p2fileinput').files;
|
||||||
|
if (xfiles != null) { var files = []; for (var i in xfiles) { if ((xfiles[i].type != null) && (xfiles[i].size != null) && (xfiles[i].size != 0) && (xfiles[i].name.endsWith('.mcrec'))) { files.push(xfiles[i]); } } }
|
||||||
|
QE('idx_dlgOkButton', files.length == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function togglePause() {
|
||||||
|
if (recFile != null) { if (playing == true) { pause(); } else { if (recFilePtr != recFile.size) { play(); } } } return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function play() {
|
||||||
|
Q('PlayButton').blur();
|
||||||
|
if ((playing == true) || (recFileProtocol == 0)) return;
|
||||||
|
playing = true;
|
||||||
|
QV('metadatadiv', false);
|
||||||
|
QE('PlayButton', false);
|
||||||
|
QE('PauseButton', true);
|
||||||
|
QE('RestartButton', false);
|
||||||
|
if ((recFileProtocol == 1) && (agentTerminal == null)) {
|
||||||
|
QV('DeskParent', false);
|
||||||
|
QV('TermParent', true);
|
||||||
|
agentTerminal = CreateAmtRemoteTerminal('Term', {});
|
||||||
|
agentTerminal.State = 3;
|
||||||
|
}
|
||||||
|
readNextBlock(processBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pause() {
|
||||||
|
Q('PauseButton').blur();
|
||||||
|
if (playing == false) return;
|
||||||
|
playing = false;
|
||||||
|
QE('PlayButton', recFilePtr != recFile.size);
|
||||||
|
QE('PauseButton', false);
|
||||||
|
QE('RestartButton', recFilePtr != 0);
|
||||||
|
if (waitTimer != null) {
|
||||||
|
clearTimeout(waitTimer);
|
||||||
|
waitTimer = null;
|
||||||
|
processBlockEx(waitTimerArgs[0], waitTimerArgs[1], waitTimerArgs[2], waitTimerArgs[3]);
|
||||||
|
waitTimerArgs = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function restart() {
|
||||||
|
Q('RestartButton').blur();
|
||||||
|
if (playing == true) return;
|
||||||
|
recFilePtr = 0;
|
||||||
|
readState = 0;
|
||||||
|
currentDeltaTimeTotalSec = 0;
|
||||||
|
QV('metadatadiv', true);
|
||||||
|
QE('PlayButton', true);
|
||||||
|
QE('PauseButton', false);
|
||||||
|
QE('RestartButton', false);
|
||||||
|
QS('progressbar').width = '0px';
|
||||||
|
QH('timespan', '00:00:00');
|
||||||
|
QV('DeskParent', true);
|
||||||
|
QV('TermParent', false);
|
||||||
|
if (agentDesktop) {
|
||||||
|
agentDesktop.Canvas.clearRect(0, 0, agentDesktop.CanvasId.width, agentDesktop.CanvasId.height);
|
||||||
|
} else if (amtDesktop) {
|
||||||
|
amtDesktop.canvas.clearRect(0, 0, amtDesktop.CanvasId.width, amtDesktop.CanvasId.height);
|
||||||
|
amtDesktop = CreateAmtRemoteDesktop('Desk');
|
||||||
|
amtDesktop.onScreenSizeChange = deskAdjust;
|
||||||
|
amtDesktop.State = 3;
|
||||||
|
amtDesktop.Start();
|
||||||
|
} else if (agentTerminal) {
|
||||||
|
agentTerminal = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearConsoleMsg() { QH('p11DeskConsoleMsg', ''); }
|
||||||
|
|
||||||
|
// Toggle the web page to full screen
|
||||||
|
function toggleAspectRatio(toggle) {
|
||||||
|
if (toggle === 1) { deskAspectRatio = ((deskAspectRatio + 1) % 3); }
|
||||||
|
deskAdjust();
|
||||||
|
}
|
||||||
|
|
||||||
|
function deskAdjust() {
|
||||||
|
var parentH = Q('DeskParent').clientHeight, parentW = Q('DeskParent').clientWidth;
|
||||||
|
var deskH = Q('Desk').height, deskW = Q('Desk').width;
|
||||||
|
|
||||||
|
if (deskAspectRatio == 2) {
|
||||||
|
// Scale mode
|
||||||
|
QS('Desk')['margin-top'] = null;
|
||||||
|
QS('Desk').height = '100%';
|
||||||
|
QS('Desk').width = '100%';
|
||||||
|
QS('DeskParent').overflow = 'hidden';
|
||||||
|
} else if (deskAspectRatio == 1) {
|
||||||
|
// Zoomed mode
|
||||||
|
QS('Desk')['margin-top'] = '0px';
|
||||||
|
//QS('Desk')['margin-left'] = '0px';
|
||||||
|
QS('Desk').height = deskH + 'px';
|
||||||
|
QS('Desk').width = deskW + 'px';
|
||||||
|
QS('DeskParent').overflow = 'scroll';
|
||||||
|
} else {
|
||||||
|
// Fixed aspect ratio
|
||||||
|
if ((parentH / parentW) > (deskH / deskW)) {
|
||||||
|
var hNew = ((deskH * parentW) / deskW) + 'px';
|
||||||
|
//if (webPageFullScreen || fullscreen) {
|
||||||
|
//QS('deskarea3x').height = null;
|
||||||
|
//} else {
|
||||||
|
// QS('deskarea3x').height = hNew;
|
||||||
|
//QS('deskarea3x').height = null;
|
||||||
|
//}
|
||||||
|
QS('Desk').height = hNew;
|
||||||
|
QS('Desk').width = '100%';
|
||||||
|
} else {
|
||||||
|
var wNew = ((deskW * parentH) / deskH) + 'px';
|
||||||
|
//if (webPageFullScreen || fullscreen) {
|
||||||
|
//QS('Desk').height = null;
|
||||||
|
//} else {
|
||||||
|
QS('Desk').height = '100%';
|
||||||
|
//}
|
||||||
|
QS('Desk').width = wNew;
|
||||||
|
}
|
||||||
|
QS('Desk')['margin-top'] = null;
|
||||||
|
QS('DeskParent').overflow = 'hidden';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POPUP DIALOG
|
||||||
|
//
|
||||||
|
|
||||||
|
// null = Hidden, 1 = Generic Message
|
||||||
|
var xxdialogMode;
|
||||||
|
var xxdialogFunc;
|
||||||
|
var xxdialogButtons;
|
||||||
|
var xxdialogTag;
|
||||||
|
var xxcurrentView = -1;
|
||||||
|
|
||||||
|
// Display a dialog box
|
||||||
|
// Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
|
||||||
|
function setDialogMode(x, y, b, f, c, tag) {
|
||||||
|
xxdialogMode = x;
|
||||||
|
xxdialogFunc = f;
|
||||||
|
xxdialogButtons = b;
|
||||||
|
xxdialogTag = tag;
|
||||||
|
QE('idx_dlgOkButton', true);
|
||||||
|
QV('idx_dlgOkButton', b & 1);
|
||||||
|
QV('idx_dlgCancelButton', b & 2);
|
||||||
|
QV('id_dialogclose', (b & 2) || (b & 8));
|
||||||
|
QV('idx_dlgDeleteButton', b & 4);
|
||||||
|
QV('idx_dlgButtonBar', b & 7);
|
||||||
|
if (y) QH('id_dialogtitle', y);
|
||||||
|
for (var i = 1; i < 3; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
|
||||||
|
QV('dialog', x);
|
||||||
|
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
|
||||||
|
}
|
||||||
|
|
||||||
|
function dialogclose(x) {
|
||||||
|
var f = xxdialogFunc, b = xxdialogButtons, t = xxdialogTag;
|
||||||
|
setDialogMode();
|
||||||
|
if (((b & 8) || x) && f) f(x, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
function messagebox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
|
||||||
|
function statusbox(t, m) { setSessionActivity(); QH('id_dialogMessage', m); setDialogMode(1, t); }
|
||||||
|
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
|
function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
|
||||||
|
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||||||
|
|
||||||
|
start();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body></html>
|
@ -42,6 +42,9 @@
|
|||||||
"info": "Information about this server"
|
"info": "Information about this server"
|
||||||
},
|
},
|
||||||
"_TlsOffload": true,
|
"_TlsOffload": true,
|
||||||
|
"_MpsPort": 44330,
|
||||||
|
"_MpsAliasPort": 4433,
|
||||||
|
"_MpsAliasHost": "mps.mydomain.com",
|
||||||
"_MpsTlsOffload": true,
|
"_MpsTlsOffload": true,
|
||||||
"_No2FactorAuth": true,
|
"_No2FactorAuth": true,
|
||||||
"_Log": "main,web,webrequest,cert",
|
"_Log": "main,web,webrequest,cert",
|
||||||
|
File diff suppressed because it is too large
Load Diff
1
views/translations/agentinvite-min_cs.handlebars
Normal file
1
views/translations/agentinvite-min_cs.handlebars
Normal file
File diff suppressed because one or more lines are too long
294
views/translations/agentinvite_cs.handlebars
Normal file
294
views/translations/agentinvite_cs.handlebars
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
<!DOCTYPE html><html><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||||
|
<title>MeshCentral - Agent Installation</title>
|
||||||
|
<style>
|
||||||
|
.tab {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button {
|
||||||
|
background-color: inherit;
|
||||||
|
float: left;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 14px 16px;
|
||||||
|
transition: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button:hover {
|
||||||
|
background-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab button.active {
|
||||||
|
background-color: #8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabcontent {
|
||||||
|
display: none;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="display:none;overflow:hidden">
|
||||||
|
<div id="container">
|
||||||
|
<!-- Begin Masthead -->
|
||||||
|
<div id="masthead" class="noselect" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden;">
|
||||||
|
<div style="float:left; height: 66px; color:#c8c8c8; padding-left:20px; padding-top:8px">
|
||||||
|
<strong><font style="font-size:46px; font-family: Arial, Helvetica, sans-serif;">{{{title}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<div style="float:left; height: 66px; color:#c8c8c8; padding-left:5px; padding-top:14px">
|
||||||
|
<strong><font style="font-size:14px; font-family: Arial, Helvetica, sans-serif;">{{{title2}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<p id="logoutControl" style="color:white;font-size:11px;margin: 10px 10px 0;">{{{logoutControl}}}</p>
|
||||||
|
</div>
|
||||||
|
<div id="page_leftbar">
|
||||||
|
<div style="height:16px"></div>
|
||||||
|
</div>
|
||||||
|
<div id="topbar" class="noselect style3" style="height:24px;position:relative">
|
||||||
|
<div id="uiMenuButton" title="User interface selection" onclick="showUserInterfaceSelectMenu()">
|
||||||
|
♦
|
||||||
|
<div id="uiMenu" style="display:none">
|
||||||
|
<div id="uiViewButton1" class="uiSelector" onclick="userInterfaceSelectMenu(1)" title="Left bar interface"><div class="uiSelector1"></div></div>
|
||||||
|
<div id="uiViewButton2" class="uiSelector" onclick="userInterfaceSelectMenu(2)" title="Top bar interface"><div class="uiSelector2"></div></div>
|
||||||
|
<div id="uiViewButton3" class="uiSelector" onclick="userInterfaceSelectMenu(3)" title="Fixed width interface"><div class="uiSelector3"></div></div>
|
||||||
|
<div id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="Toggle night mode"><div class="uiSelector4"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="column_l" style="max-height:calc(100vh - 135px);overflow-y:auto">
|
||||||
|
<h1>Instalace agenta pro vzdálený přístup<span id="groupname"></span></h1>
|
||||||
|
<p>
|
||||||
|
Byla vám doručena pozvánka k instalaci softwaru, který umožňuje vzdálenou správu zařízení.
|
||||||
|
Postupujte podle níže uvedených pokynů, pokud jste si vědom toho, že tato pozvánka je legitimní a chcete tento přístup umožnit.
|
||||||
|
Vyberte si operační systém a postupujte dle pokynů níže.
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<div class="tab">
|
||||||
|
<button id="twintab64" class="tablinks" onclick="openTab(event, 'wintab64')">Windows 64bit</button>
|
||||||
|
<button id="twintab32" class="tablinks" onclick="openTab(event, 'wintab32')">Windows 32bit</button>
|
||||||
|
<button id="tlinuxtab" class="tablinks" onclick="openTab(event, 'linuxtab')">Linux</button>
|
||||||
|
<button id="tmacostab" class="tablinks" onclick="openTab(event, 'macostab')">MacOS</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="wintab64" class="tabcontent" style="background-color:white;color:black">
|
||||||
|
<h3>Microsoft™ Windows 64bit</h3>
|
||||||
|
<p><a id="win64url">Download the software here</a>, spusťte soubor a zvolte "Install" nebo "Connect".</p>
|
||||||
|
<div style="text-align:center">
|
||||||
|
<img class="winagent-img" src="images/winagent.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="wintab32" class="tabcontent" style="background-color:white;color:black">
|
||||||
|
<h3>Microsoft™ Windows 32bit</h3>
|
||||||
|
<p><a id="win32url">Download the software here</a>, spusťte soubor a zvolte "Install" nebo "Connect".</p>
|
||||||
|
<div style="text-align:center">
|
||||||
|
<img class="winagent-img" src="images/winagent.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="linuxtab" class="tabcontent" style="background-color:white;color:black">
|
||||||
|
<h3>Linux</h3>
|
||||||
|
<p>Pro instalaci spusťte následující příkaz s právy uživatele root.</p>
|
||||||
|
<div id="linuxinstall" style="font-family:courier,'courier new',monospace;margin-left:30px"></div>
|
||||||
|
<input type="button" value="Zkopírovat do schránky" style="margin-left:30px;margin-top:4px" onclick="copyToClipLinuxInstall()">
|
||||||
|
<p>Pro odinstalování spustťe tento příkaz pod s uživatelskými právy root.</p>
|
||||||
|
<div id="unlinuxinstall" style="font-family:courier,'courier new',monospace;margin-left:30px"></div>
|
||||||
|
<input type="button" value="Zkopírovat do schránky" style="margin-left:30px;margin-top:4px" onclick="copyToClipLinuxUnInstall()">
|
||||||
|
<br><br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="macostab" class="tabcontent" style="background-color:white;color:black">
|
||||||
|
<h3>Apple™ MacOS</h3>
|
||||||
|
<p><a id="macosurl">Stáhnout instalaci zde</a>, poté spusťe instalaci. Postupujte dle instrukcí.</p>
|
||||||
|
<div style="text-align:center">
|
||||||
|
<img src="images/macosagent.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<table cellpadding="0" cellspacing="10" style="width: 100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="text-align:left"></td>
|
||||||
|
<td style="text-align:right"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
var uiMode = parseInt(getstore('uiMode', 1));
|
||||||
|
var webPageStackMenu = false;
|
||||||
|
var webPageFullScreen = true;
|
||||||
|
var nightMode = (getstore('_nightMode', '0') == '1');
|
||||||
|
var domain = "{{{domain}}}";
|
||||||
|
var domainUrl = "{{{domainurl}}}";
|
||||||
|
var meshid = "{{{meshid}}}";
|
||||||
|
var serverPort = "{{{serverport}}}";
|
||||||
|
var serverHttps = "{{{serverhttps}}}";
|
||||||
|
var serverNoProxy = "{{{servernoproxy}}}";
|
||||||
|
var installFlags = "{{{installflags}}}";
|
||||||
|
var groupName = decodeURIComponent("{{{meshname}}}");
|
||||||
|
if (groupName != '') { QH('groupname', ' for ' + groupName); }
|
||||||
|
userInterfaceSelectMenu();
|
||||||
|
setup();
|
||||||
|
|
||||||
|
// Toggle user interface menu
|
||||||
|
function showUserInterfaceSelectMenu() {
|
||||||
|
Q('uiViewButton1').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton2').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton3').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton4').classList.remove('uiSelectorSel');
|
||||||
|
try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
|
||||||
|
QV('uiMenu', (QS('uiMenu').display == 'none'));
|
||||||
|
if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function userInterfaceSelectMenu(s) {
|
||||||
|
if (s) { uiMode = s; putstore('uiMode', uiMode); }
|
||||||
|
webPageFullScreen = (uiMode < 3);
|
||||||
|
webPageStackMenu = true;//(uiMode > 1);
|
||||||
|
toggleFullScreen(0);
|
||||||
|
toggleStackMenu(0);
|
||||||
|
QC('column_l').add('room4submenu');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleNightMode() {
|
||||||
|
nightMode = !nightMode;
|
||||||
|
if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
|
||||||
|
putstore('_nightMode', nightMode ? '1' : '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the web page to full screen
|
||||||
|
function toggleFullScreen(toggle) {
|
||||||
|
if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
|
||||||
|
var hide = 0;
|
||||||
|
//if (args.hide) { hide = parseInt(args.hide); }
|
||||||
|
if (webPageFullScreen == false) {
|
||||||
|
QC('body').remove("menu_stack");
|
||||||
|
QC('body').remove("fullscreen");
|
||||||
|
QC('body').remove("arg_hide");
|
||||||
|
//if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
|
||||||
|
//QV('UserDummyMenuSpan', false);
|
||||||
|
//QV('page_leftbar', false);
|
||||||
|
} else {
|
||||||
|
QC('body').add("fullscreen");
|
||||||
|
if (hide & 16) QC('body').add("arg_hide"); // This is replacement for QV('page_leftbar', !(hide & 16));
|
||||||
|
//QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
|
||||||
|
//QV('page_leftbar', true);
|
||||||
|
}
|
||||||
|
QV('body', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If FullScreen, toggle menu to be horisontal or vertical
|
||||||
|
function toggleStackMenu(toggle) {
|
||||||
|
if (webPageFullScreen == true) {
|
||||||
|
if (toggle === 1) {
|
||||||
|
webPageStackMenu = !webPageStackMenu;
|
||||||
|
putstore('webPageStackMenu', webPageStackMenu);
|
||||||
|
}
|
||||||
|
if (webPageStackMenu == false) {
|
||||||
|
QC('body').remove("menu_stack");
|
||||||
|
} else {
|
||||||
|
QC('body').add("menu_stack");
|
||||||
|
//if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
|
||||||
|
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
|
||||||
|
|
||||||
|
function openTab(evt, tabname) {
|
||||||
|
// Declare all variables
|
||||||
|
var i, tabcontent, tablinks;
|
||||||
|
|
||||||
|
// Get all elements with class="tabcontent" and hide them
|
||||||
|
tabcontent = document.getElementsByClassName("tabcontent");
|
||||||
|
for (i = 0; i < tabcontent.length; i++) {
|
||||||
|
tabcontent[i].style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all elements with class="tablinks" and remove the class "active"
|
||||||
|
tablinks = document.getElementsByClassName("tablinks");
|
||||||
|
for (i = 0; i < tablinks.length; i++) {
|
||||||
|
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the current tab, and add an "active" class to the button that opened the tab
|
||||||
|
document.getElementById(tabname).style.display = "block";
|
||||||
|
if (evt != null) { evt.currentTarget.className += " active"; } else { document.getElementById('t' + tabname).className += " active"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
var linuxInstall, linuxUnInstall;
|
||||||
|
function setup() {
|
||||||
|
var servername = window.location.hostname;
|
||||||
|
var domainUrlNoSlash = domainUrl.substring(0, domainUrl.length - 1);
|
||||||
|
|
||||||
|
// Windows 64bit Setup
|
||||||
|
var url = 'meshagents?id=4&meshid=' + meshid;
|
||||||
|
if (installFlags != 0) { url += ('&installflags=' + installFlags); }
|
||||||
|
Q('win64url').href = url;
|
||||||
|
|
||||||
|
// Windows 32bit Setup
|
||||||
|
url = 'meshagents?id=3&meshid=' + meshid;
|
||||||
|
if (installFlags != 0) { url += ('&installflags=' + installFlags); }
|
||||||
|
Q('win32url').href = url;
|
||||||
|
|
||||||
|
// MacOS Setup
|
||||||
|
url = 'meshosxagent?id=16&meshid=' + meshid;
|
||||||
|
Q('macosurl').href = url;
|
||||||
|
|
||||||
|
// Linux Setup
|
||||||
|
if (serverHttps == 1) {
|
||||||
|
var portStr = (serverPort == 443) ? '' : (":" + serverPort);
|
||||||
|
if (serverNoProxy == 0) {
|
||||||
|
linuxInstall = "(wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://" + servername + portStr + domainUrlNoSlash + " '" + meshid + "'\r\n";
|
||||||
|
linuxUnInstall = "(wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-check-certificate -O ./meshinstall.sh || wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
|
||||||
|
} else {
|
||||||
|
// Server asked that agent be installed to preferably not use a HTTP proxy.
|
||||||
|
linuxInstall = "wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh https://" + servername + portStr + domainUrlNoSlash + " '" + meshid + "'\r\n";
|
||||||
|
linuxUnInstall = "wget https://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy --no-check-certificate -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var portStr = (serverPort == 80) ? '' : (":" + serverPort);
|
||||||
|
if (serverNoProxy == 0) {
|
||||||
|
linuxInstall = "(wget http://" + servername + portStr + domainUrl + "meshagents?script=1 -O ./meshinstall.sh || wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://" + servername + portStr + domainUrlNoSlash + " '" + meshid + "'\r\n";
|
||||||
|
linuxUnInstall = "(wget http://" + servername + portStr + domainUrl + "meshagents?script=1 -O ./meshinstall.sh || wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh) && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
|
||||||
|
} else {
|
||||||
|
// Server asked that agent be installed to preferably not use a HTTP proxy.
|
||||||
|
linuxInstall = "wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh http://" + servername + portStr + domainUrlNoSlash + " '" + meshid + "'\r\n";
|
||||||
|
linuxUnInstall = "wget http://" + servername + portStr + domainUrl + "meshagents?script=1 --no-proxy -O ./meshinstall.sh && chmod 755 ./meshinstall.sh && sudo ./meshinstall.sh uninstall\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QH('linuxinstall', linuxInstall);
|
||||||
|
QH('unlinuxinstall', linuxUnInstall);
|
||||||
|
|
||||||
|
// Attempt to detect the most likely operating system for this browser
|
||||||
|
if (navigator.userAgent.indexOf('Win64') >= 0) { openTab(null, 'wintab64'); }
|
||||||
|
else if (navigator.userAgent.indexOf('Windows') >= 0) { openTab(null, 'wintab32'); }
|
||||||
|
else if (navigator.userAgent.indexOf('Linux') >= 0) { openTab(null, 'linuxtab'); }
|
||||||
|
else if (navigator.userAgent.indexOf('Macintosh') >= 0) { openTab(null, 'macostab'); }
|
||||||
|
else { openTab(null, 'wintab64'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyToClipLinuxInstall() { copyTextToClip(linuxInstall); }
|
||||||
|
function copyToClipLinuxUnInstall() { copyTextToClip(linuxUnInstall); }
|
||||||
|
function copyTextToClip(txt) { function selectElementText(e) { if (document.selection) { var range = document.body.createTextRange(); range.moveToElementText(e); range.select(); } else if (window.getSelection) { var range = document.createRange(); range.selectNode(e); window.getSelection().removeAllRanges(); window.getSelection().addRange(range); } } var e = document.createElement('DIV'); e.textContent = txt; document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body></html>
|
8694
views/translations/default-min_cs.handlebars
Normal file
8694
views/translations/default-min_cs.handlebars
Normal file
File diff suppressed because one or more lines are too long
1
views/translations/default-mobile-min_cs.handlebars
Normal file
1
views/translations/default-mobile-min_cs.handlebars
Normal file
File diff suppressed because one or more lines are too long
3391
views/translations/default-mobile_cs.handlebars
Normal file
3391
views/translations/default-mobile_cs.handlebars
Normal file
File diff suppressed because it is too large
Load Diff
9721
views/translations/default_cs.handlebars
Normal file
9721
views/translations/default_cs.handlebars
Normal file
File diff suppressed because it is too large
Load Diff
1
views/translations/download-min_cs.handlebars
Normal file
1
views/translations/download-min_cs.handlebars
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!doctypehtml><html dir=ltr xmlns=http://www.w3.org/1999/xhtml><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html;charset=utf-8"http-equiv=Content-Type><meta name=viewport content="user-scalable=1,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name=apple-mobile-web-app-capable content=yes><meta name=format-detection content="telephone=no"><link type=text/css href=/styles/style.css media=screen rel=stylesheet title=CSS><title>MeshCentral - Download</title><div id=container style=max-height:100vh><div id=mastheadx></div><div id=masthead style="background:url(logo.png) 0 0;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden"><div style=float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px><strong><font style=font-size:46px;font-family:Arial,Helvetica,sans-serif>{{{title}}}</font></strong></div><div style=float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px><strong><font style=font-size:14px;font-family:Arial,Helvetica,sans-serif>{{{title2}}}</font></strong></div></div><div id=page_content style=max-height:calc(100vh-138px)><div id=column_l><h1>Stažení</h1><p style=margin-left:20px>{{{message}}}</p><br></div><div id=footer><table cellpadding=0 cellspacing=10 style=width:100%><tr><td style=text-align:left><td style=text-align:right>{{{rootCertLink}}} <a href=terms>Terms & Privacy</a></table></div></div></div>
|
41
views/translations/download_cs.handlebars
Normal file
41
views/translations/download_cs.handlebars
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link type="text/css" href="/styles/style.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<title>MeshCentral - Download</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container" style="max-height:100vh">
|
||||||
|
<div id="mastheadx"></div>
|
||||||
|
<div id="masthead" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden">
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px">
|
||||||
|
<strong><font style="font-size:46px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px">
|
||||||
|
<strong><font style="font-size:14px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="page_content" style="max-height:calc(100vh-138px)">
|
||||||
|
<div id="column_l">
|
||||||
|
<h1>Stažení</h1>
|
||||||
|
<p style="margin-left:20px">{{{message}}}</p>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<table cellpadding="0" cellspacing="10" style="width:100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="text-align:left"></td>
|
||||||
|
<td style="text-align:right">
|
||||||
|
{{{rootCertLink}}}
|
||||||
|
<a href="terms">Terms & Privacy</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body></html>
|
1
views/translations/error404-min_cs.handlebars
Normal file
1
views/translations/error404-min_cs.handlebars
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!doctypehtml><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html; charset=utf-8"http-equiv=Content-Type><meta name=viewport content="user-scalable=1,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name=apple-mobile-web-app-capable content=yes><meta name=format-detection content="telephone=no"><link type=text/css href=styles/style.css media=screen rel=stylesheet title=CSS><script src=scripts/common-0.0.1.js></script><title>MeshCentral - Terms of use</title><body id=body onload='"undefined"!=typeof startup&&startup()'style=display:none;overflow:hidden><div id=container><div id=masthead class=noselect style="background:url(logo.png) 0 0;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden"><div style=float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px><strong><font style=font-size:46px;font-family:Arial,Helvetica,sans-serif>{{{title}}}</font></strong></div><div style=float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px><strong><font style=font-size:14px;font-family:Arial,Helvetica,sans-serif>{{{title2}}}</font></strong></div><p id=logoutControl style="color:#fff;font-size:11px;margin:10px 10px 0">{{{logoutControl}}}</div><div id=page_leftbar><div style=height:16px></div></div><div id=topbar class="noselect style3"style=height:24px;position:relative><div id=uiMenuButton title="User interface selection"onclick=showUserInterfaceSelectMenu()>♦<div id=uiMenu style=display:none><div id=uiViewButton1 class=uiSelector onclick=userInterfaceSelectMenu(1) title="Left bar interface"><div class=uiSelector1></div></div><div id=uiViewButton2 class=uiSelector onclick=userInterfaceSelectMenu(2) title="Top bar interface"><div class=uiSelector2></div></div><div id=uiViewButton3 class=uiSelector onclick=userInterfaceSelectMenu(3) title="Fixed width interface"><div class=uiSelector3></div></div><div id=uiViewButton4 class=uiSelector onclick=toggleNightMode() title="Toggle night mode"><div class=uiSelector4></div></div></div></div></div><div id=column_l style="max-height:calc(100vh - 135px);overflow-y:auto"><div style=text-align:center;padding-top:30px;font-size:200px;font-family:Arial;color:#bbb><b>404</b></div><div style=text-align:center;font-size:20px;font-family:Arial;color:#999>Tato stránka neexistuje</div><div style=text-align:center;padding-top:20px;font-size:20px;font-family:Arial;color:#999><a href=/ style=text-decoration:none><b>Go to main site</b></a></div></div><div id=footer><table cellpadding=0 cellspacing=10 style=width:100%><tr><td style=text-align:left><td style=text-align:right><a href=/ >Zpět</a></table></div></div><script>"use strict";var uiMode=parseInt(getstore("uiMode",1)),webPageStackMenu=!1,webPageFullScreen=!0,nightMode="1"==getstore("_nightMode","0"),terms="{{{terms}}}";function showUserInterfaceSelectMenu(){Q("uiViewButton1").classList.remove("uiSelectorSel"),Q("uiViewButton2").classList.remove("uiSelectorSel"),Q("uiViewButton3").classList.remove("uiSelectorSel"),Q("uiViewButton4").classList.remove("uiSelectorSel");try{Q("uiViewButton"+uiMode).classList.add("uiSelectorSel")}catch(e){}QV("uiMenu","none"==QS("uiMenu").display),nightMode&&Q("uiViewButton4").classList.add("uiSelectorSel")}function userInterfaceSelectMenu(e){e&&putstore("uiMode",uiMode=e),webPageFullScreen=uiMode<3,webPageStackMenu=!0,toggleFullScreen(0),toggleStackMenu(0),QC("column_l").add("room4submenu")}function toggleNightMode(){(nightMode=!nightMode)?QC("body").add("night"):QC("body").remove("night"),putstore("_nightMode",nightMode?"1":"0")}function toggleFullScreen(e){1===e&&putstore("webPageFullScreen",webPageFullScreen=!webPageFullScreen);0==webPageFullScreen?(QC("body").remove("menu_stack"),QC("body").remove("fullscreen"),QC("body").remove("arg_hide")):QC("body").add("fullscreen"),QV("body",!0)}function toggleStackMenu(e){1==webPageFullScreen&&(1===e&&putstore("webPageStackMenu",webPageStackMenu=!webPageStackMenu),0==webPageStackMenu?QC("body").remove("menu_stack"):QC("body").add("menu_stack"))}function putstore(e,t){try{if("undefined"==typeof localStorage)return;localStorage.setItem(e,t)}catch(e){}}function getstore(e,t){try{if("undefined"==typeof localStorage)return t;var o=localStorage.getItem(e);return null==o||null==o?t:o}catch(e){return t}}""!=terms&&QH("column_l",decodeURIComponent(terms)),QV("column_l",!0),userInterfaceSelectMenu()</script>
|
1
views/translations/error404-mobile-min_cs.handlebars
Normal file
1
views/translations/error404-mobile-min_cs.handlebars
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!doctypehtml><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html; charset=utf-8"http-equiv=Content-Type><meta name=viewport content="user-scalable=1,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name=apple-mobile-web-app-capable content=yes><meta name=format-detection content="telephone=no"><title>MeshCentral - Terms of use</title><style type=text/css>a{color:#036;text-decoration:underline}#footer a{color:#fff;text-decoration:underline}#footer a:hover{color:#fff;text-decoration:none}</style><body onload='"undefined"!=typeof startup&&startup()'style="overflow-y:hidden;max-width:100%;margin:0;padding:0;border:0;color:#000;font-size:13px;font-family:\'Trebuchet MS\',Arial,Helvetica,sans-serif"><div id=container><div id=masthead style="background:url(logo.png) 0 0;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden"><div style=float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:4px><strong><font style=font-size:36px;font-family:Arial,Helvetica,sans-serif>{{{title}}}</font></strong></div><div style=float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:7px><strong><font style=font-size:12px;font-family:Arial,Helvetica,sans-serif>{{{title2}}}</font></strong></div><p>{{{logoutControl}}}</div><div id=page_content style=overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%><div id=column_l style=padding-left:10px;padding-right:10px><div style=text-align:center;padding-top:30px;font-size:100px;font-family:Arial;color:#bbb><b>404</b></div><div style=text-align:center;font-size:16px;font-family:Arial;color:#999>Tato stránka neexistuje</div><div style=text-align:center;padding-top:16px;font-size:20px;font-family:Arial;color:#999><a href=/ style=text-decoration:none><b>Go to main site</b></a></div></div></div><div id=footer style=height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0><table cellpadding=0 cellspacing=6 style=width:100%><tr><td style=text-align:left;color:#fff>{{{footer}}}<td style=text-align:right>{{{rootCertLink}}} <a href=/ >Zpět</a></table></div></div>
|
55
views/translations/error404-mobile_cs.handlebars
Normal file
55
views/translations/error404-mobile_cs.handlebars
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<!DOCTYPE html><html><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<title>MeshCentral - Terms of use</title>
|
||||||
|
<style type="text/css">
|
||||||
|
a {
|
||||||
|
color: #036;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer a:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;max-width:100%;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
|
||||||
|
<div id="container">
|
||||||
|
<!-- Begin Masthead -->
|
||||||
|
<div id="masthead" style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:4px">
|
||||||
|
<strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:7px">
|
||||||
|
<strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<p>{{{logoutControl}}}</p>
|
||||||
|
</div>
|
||||||
|
<div id="page_content" style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%">
|
||||||
|
<div id="column_l" style="padding-left:10px;padding-right:10px">
|
||||||
|
<div style="text-align:center;padding-top:30px;font-size:100px;font-family:Arial;color:#bbb"><b>404</b></div>
|
||||||
|
<div style="text-align:center;font-size:16px;font-family:Arial;color:#999">Tato stránka neexistuje</div>
|
||||||
|
<div style="text-align:center;padding-top:16px;font-size:20px;font-family:Arial;color:#999"><a href="/" style="text-decoration:none"><b>Go to main site</b></a></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="footer" style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px">
|
||||||
|
<table cellpadding="0" cellspacing="6" style="width:100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="text-align:left;color:white">{{{footer}}}</td>
|
||||||
|
<td style="text-align:right">{{{rootCertLink}}} <a href="/">Zpět</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body></html>
|
132
views/translations/error404_cs.handlebars
Normal file
132
views/translations/error404_cs.handlebars
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<!DOCTYPE html><html><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||||
|
<title>MeshCentral - Terms of use</title>
|
||||||
|
</head>
|
||||||
|
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="display:none;overflow:hidden">
|
||||||
|
<div id="container">
|
||||||
|
<!-- Begin Masthead -->
|
||||||
|
<div id="masthead" class="noselect" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden;">
|
||||||
|
<div style="float:left; height: 66px; color:#c8c8c8; padding-left:20px; padding-top:8px">
|
||||||
|
<strong><font style="font-size:46px; font-family: Arial, Helvetica, sans-serif;">{{{title}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<div style="float:left; height: 66px; color:#c8c8c8; padding-left:5px; padding-top:14px">
|
||||||
|
<strong><font style="font-size:14px; font-family: Arial, Helvetica, sans-serif;">{{{title2}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<p id="logoutControl" style="color:white;font-size:11px;margin: 10px 10px 0;">{{{logoutControl}}}</p>
|
||||||
|
</div>
|
||||||
|
<div id="page_leftbar">
|
||||||
|
<div style="height:16px"></div>
|
||||||
|
</div>
|
||||||
|
<div id="topbar" class="noselect style3" style="height:24px;position:relative">
|
||||||
|
<div id="uiMenuButton" title="User interface selection" onclick="showUserInterfaceSelectMenu()">
|
||||||
|
♦
|
||||||
|
<div id="uiMenu" style="display:none">
|
||||||
|
<div id="uiViewButton1" class="uiSelector" onclick="userInterfaceSelectMenu(1)" title="Left bar interface"><div class="uiSelector1"></div></div>
|
||||||
|
<div id="uiViewButton2" class="uiSelector" onclick="userInterfaceSelectMenu(2)" title="Top bar interface"><div class="uiSelector2"></div></div>
|
||||||
|
<div id="uiViewButton3" class="uiSelector" onclick="userInterfaceSelectMenu(3)" title="Fixed width interface"><div class="uiSelector3"></div></div>
|
||||||
|
<div id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="Toggle night mode"><div class="uiSelector4"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="column_l" style="max-height:calc(100vh - 135px);overflow-y:auto">
|
||||||
|
<div style="text-align:center;padding-top:30px;font-size:200px;font-family:Arial;color:#bbb"><b>404</b></div>
|
||||||
|
<div style="text-align:center;font-size:20px;font-family:Arial;color:#999">Tato stránka neexistuje</div>
|
||||||
|
<div style="text-align:center;padding-top:20px;font-size:20px;font-family:Arial;color:#999"><a href="/" style="text-decoration:none"><b>Go to main site</b></a></div>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<table cellpadding="0" cellspacing="10" style="width: 100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="text-align:left"></td>
|
||||||
|
<td style="text-align:right"><a href="/">Zpět</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
var uiMode = parseInt(getstore('uiMode', 1));
|
||||||
|
var webPageStackMenu = false;
|
||||||
|
var webPageFullScreen = true;
|
||||||
|
var nightMode = (getstore('_nightMode', '0') == '1');
|
||||||
|
|
||||||
|
var terms = '{{{terms}}}';
|
||||||
|
if (terms != '') { QH('column_l', decodeURIComponent(terms)); }
|
||||||
|
QV('column_l', true);
|
||||||
|
userInterfaceSelectMenu();
|
||||||
|
|
||||||
|
// Toggle user interface menu
|
||||||
|
function showUserInterfaceSelectMenu() {
|
||||||
|
Q('uiViewButton1').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton2').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton3').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton4').classList.remove('uiSelectorSel');
|
||||||
|
try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
|
||||||
|
QV('uiMenu', (QS('uiMenu').display == 'none'));
|
||||||
|
if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function userInterfaceSelectMenu(s) {
|
||||||
|
if (s) { uiMode = s; putstore('uiMode', uiMode); }
|
||||||
|
webPageFullScreen = (uiMode < 3);
|
||||||
|
webPageStackMenu = true;//(uiMode > 1);
|
||||||
|
toggleFullScreen(0);
|
||||||
|
toggleStackMenu(0);
|
||||||
|
QC('column_l').add('room4submenu');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleNightMode() {
|
||||||
|
nightMode = !nightMode;
|
||||||
|
if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
|
||||||
|
putstore('_nightMode', nightMode ? '1' : '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the web page to full screen
|
||||||
|
function toggleFullScreen(toggle) {
|
||||||
|
if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
|
||||||
|
var hide = 0;
|
||||||
|
//if (args.hide) { hide = parseInt(args.hide); }
|
||||||
|
if (webPageFullScreen == false) {
|
||||||
|
QC('body').remove('menu_stack');
|
||||||
|
QC('body').remove('fullscreen');
|
||||||
|
QC('body').remove('arg_hide');
|
||||||
|
//if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
|
||||||
|
//QV('UserDummyMenuSpan', false);
|
||||||
|
//QV('page_leftbar', false);
|
||||||
|
} else {
|
||||||
|
QC('body').add('fullscreen');
|
||||||
|
if (hide & 16) QC('body').add('arg_hide'); // This is replacement for QV('page_leftbar', !(hide & 16));
|
||||||
|
//QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
|
||||||
|
//QV('page_leftbar', true);
|
||||||
|
}
|
||||||
|
QV('body', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If FullScreen, toggle menu to be horisontal or vertical
|
||||||
|
function toggleStackMenu(toggle) {
|
||||||
|
if (webPageFullScreen == true) {
|
||||||
|
if (toggle === 1) {
|
||||||
|
webPageStackMenu = !webPageStackMenu;
|
||||||
|
putstore('webPageStackMenu', webPageStackMenu);
|
||||||
|
}
|
||||||
|
if (webPageStackMenu == false) {
|
||||||
|
QC('body').remove('menu_stack');
|
||||||
|
} else {
|
||||||
|
QC('body').add('menu_stack');
|
||||||
|
//if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
|
||||||
|
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body></html>
|
1
views/translations/login-min_cs.handlebars
Normal file
1
views/translations/login-min_cs.handlebars
Normal file
File diff suppressed because one or more lines are too long
1
views/translations/login-mobile-min_cs.handlebars
Normal file
1
views/translations/login-mobile-min_cs.handlebars
Normal file
File diff suppressed because one or more lines are too long
647
views/translations/login-mobile_cs.handlebars
Normal file
647
views/translations/login-mobile_cs.handlebars
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico">
|
||||||
|
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/u2f-api.js"></script>
|
||||||
|
<title>MeshCentral - Login</title>
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
color: #036;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer a:hover {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
|
||||||
|
<div id="container">
|
||||||
|
<div id="mastheadx"></div>
|
||||||
|
<div id="masthead" style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden">
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:6px">
|
||||||
|
<strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:10px">
|
||||||
|
<strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="page_content" style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%;display:flex;align-items:center">
|
||||||
|
<div id="column_l" style="padding:10px;width:100%">
|
||||||
|
<table style="width:100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="center">
|
||||||
|
<div id="loginpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;display:none">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="login">
|
||||||
|
<div id="message1"></div>
|
||||||
|
<div>
|
||||||
|
<b>Přihlásit</b>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td id="loginusername" align="right" width="100">Uživatel:</td>
|
||||||
|
<td><input id="username" type="text" maxlength="64" name="username" onchange="validateLogin(1)" onkeyup="validateLogin(1,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">Heslo:</td>
|
||||||
|
<td><input id="password" type="password" maxlength="256" name="password" autocomplete="off" onchange="validateLogin(2)" onkeyup="validateLogin(2,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><div id="showPassHintLink" style="display:none"><a onclick="showPassHint()" style="cursor:pointer">Show Hint</a></div></td>
|
||||||
|
<td align="right"><input id="loginButton" type="submit" value="Přihlásit" disabled="disabled"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<div id="hrAccountDiv" style="display:none"><hr></div>
|
||||||
|
<div id="resetAccountDiv" style="display:none;padding:2px">
|
||||||
|
<span id="resetAccountSpan">Forgot user/password?</span> <a onclick="xgo(3)" style="cursor:pointer">Reset účtu</a>.
|
||||||
|
</div>
|
||||||
|
<div id="newAccountDiv" style="display:none;padding:2px">
|
||||||
|
Nemáte účet? <a onclick="xgo(2)" style="cursor:pointer">Vytvořit</a>.
|
||||||
|
</div>
|
||||||
|
<input id="loginformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="createpanel" style="display:none">
|
||||||
|
<div style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;clear:both;position:relative">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="createaccount">
|
||||||
|
<div id="message2"></div>
|
||||||
|
<div>
|
||||||
|
<b>Account Creation</b>
|
||||||
|
</div>
|
||||||
|
<div id="passwordPolicyCallout" style="left:-5px;top:10px;width:100px;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr id="nuUserRow">
|
||||||
|
<td align="right" width="100">Uživatel:</td>
|
||||||
|
<td><input id="ausername" type="text" name="username" onchange="validateCreate(1)" maxlength="64" onkeydown="haltReturn(event)" onkeyup="validateCreate(1,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right" width="100">Email:</td>
|
||||||
|
<td><input id="aemail" type="text" name="email" onchange="validateCreate(2)" maxlength="256" onkeydown="haltReturn(event)" onkeyup="validateCreate(2,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">Heslo:</td>
|
||||||
|
<td><input id="apassword1" type="password" name="password1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(3)" onkeyup="validateCreate(3,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">Heslo:</td>
|
||||||
|
<td><input id="apassword2" type="password" name="password2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(4)" onkeyup="validateCreate(4,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="createPanelHint" style="display:none">
|
||||||
|
<td align="right">Nápověda k heslu:</td>
|
||||||
|
<td><input id="apasswordhint" type="text" name="apasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(5)" onkeyup="validateCreate(5,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="newAccountPass" title="Enter the account creation token">
|
||||||
|
<td align="right">Creation Token:</td>
|
||||||
|
<td><input id="anewaccountpass" type="password" name="anewaccountpass" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(6)" onkeyup="validateCreate(6,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="createButton" type="submit" value="Create Account" disabled="disabled"></div>
|
||||||
|
<div id="passWarning" style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="createformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="resetpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
|
<div id="message3"></div>
|
||||||
|
<div>
|
||||||
|
<b>Reset hesla</b>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="right" width="100">Email:</td>
|
||||||
|
<td><input id="remail" type="text" name="email" maxlength="256" onchange="validateReset()" onkeyup="validateReset(event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="eresetButton" type="submit" value="Reset účtu" disabled="disabled"></div>
|
||||||
|
<div id="passWarning" style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="resetformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="tokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
|
<form method="post" autocomplete="off">
|
||||||
|
<input type="hidden" name="action" value="tokenlogin">
|
||||||
|
<input type="hidden" name="hwstate" value="{{{hwstate}}}">
|
||||||
|
<div id="message4"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="right" width="100">Login token:</td>
|
||||||
|
<td>
|
||||||
|
<input id="tokenInput" type="text" name="token" maxlength="50" onchange="checkToken(event)" onkeyup="checkToken(event)" onkeydown="checkToken(event)" onfocus="checkTokenTimer(1)" onblur="checkTokenTimer(0)">
|
||||||
|
<input id="hwtokenInput" type="text" name="hwtoken" style="display:none">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="align-content:center">
|
||||||
|
<label><input id="tokenInputRemember" name="remembertoken" type="checkbox">Remember this device for 30 days.</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="tokenOkButton" type="submit" value="Login" disabled="disabled"></div>
|
||||||
|
<div style="float:right"><input style="display:none;float:right" id="securityKeyButton" type="button" value="Use Security Key" onclick="useSecurityKey()"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="tokenformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="resettokenpanel" style="background-color:#979797;border-radius:16px;width:260px;padding:16px;text-align:center;display:none;clear:both">
|
||||||
|
<form method="post" autocomplete="off">
|
||||||
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
|
<div id="message5"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="right" width="100">Login token:</td>
|
||||||
|
<td>
|
||||||
|
<input id="resetTokenInput" type="text" name="token" maxlength="50" onchange="resetCheckToken(event)" onpaste="resetCheckToken(event)" onkeyup="resetCheckToken(event)" onkeydown="resetCheckToken(event)">
|
||||||
|
<input id="resetHwtokenInput" type="text" name="hwtoken" style="display:none">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="resetTokenOkButton" type="submit" value="Login" disabled="disabled"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="resettokenformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="resetpasswordpanel" style="position:relative;background-color:#979797;border-radius:16px;width:300px;padding:16px;text-align:center;display:none">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="resetpassword">
|
||||||
|
<div id="message6"></div>
|
||||||
|
<div id="rpasswordPolicyCallout" style="left:-10px;width:100px;display:none;position:absolute;background-color:#FFC;border-radius:5px;padding:5px;box-shadow:0px 0px 15px #666;font-size:10px"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td id="rnuPass1" width="100" align="right">Heslo:</td>
|
||||||
|
<td><input id="rapassword1" type="password" name="rpassword1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(3,event)" onkeyup="validatePassReset(3,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuPass2" align="right">Heslo:</td>
|
||||||
|
<td><input id="rapassword2" type="password" name="rpassword2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(4,event)" onkeyup="validatePassReset(4,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="resetpasswordpanelHint" style="display:none">
|
||||||
|
<td id="rnuHint" align="right">Password Hint:</td>
|
||||||
|
<td><input id="rapasswordhint" type="text" name="rpasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(5,event)" onkeyup="validatePassReset(5,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="resetPassButton" type="submit" value="Reset hesla" disabled="disabled"></div>
|
||||||
|
<div id="rpassWarning" style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="xgo(1)" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="resetpasswordformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="footer" style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px">
|
||||||
|
<table cellpadding="0" cellspacing="6" style="width:100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="text-align:left;color:white">{{{footer}}}</td>
|
||||||
|
<td style="text-align:right">{{{rootCertLink}}} <a href="terms">Terms & Privacy</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="dialog" style="z-index:1000;background-color:#EEE;box-shadow:0px 0px 15px #666;font-family:Arial,Helvetica,sans-serif;border-radius:5px;position:fixed;top:180px;width:400px;display:none">
|
||||||
|
<div style="width:100%;background-color:#003366;color:#FFF;border-radius:5px 5px 0 0">
|
||||||
|
<div id="id_dialogclose" style="float:right;padding:5px;cursor:pointer" onclick="setDialogMode()"><b>X</b></div>
|
||||||
|
<div id="id_dialogtitle" style="padding:5px"></div>
|
||||||
|
<div style="width:100%;margin:6px"></div>
|
||||||
|
</div>
|
||||||
|
<div style="margin-right:16px;margin-left:8px">
|
||||||
|
<div id="dialog1" style="margin:auto;text-align:center;margin:3px">
|
||||||
|
<div id="id_dialogMessage" style="padding:10px"></div>
|
||||||
|
</div>
|
||||||
|
<div id="dialog2" style="margin:auto;margin:3px">
|
||||||
|
<div id="id_dialogOptions"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="idx_dlgButtonBar" style="padding:10px;margin-bottom:20px">
|
||||||
|
<input id="idx_dlgCancelButton" type="button" value="Zrušit" style="float:right;width:80px;margin-left:5px" onclick="dialogclose(0)">
|
||||||
|
<input id="idx_dlgOkButton" type="button" value="OK" style="float:right;width:80px" onclick="dialogclose(1)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
var loginMode = '{{{loginmode}}}';
|
||||||
|
var newAccount = '{{{newAccount}}}';
|
||||||
|
var passhint = '{{{passhint}}}';
|
||||||
|
var newAccountPass = parseInt('{{{newAccountPass}}}');
|
||||||
|
var emailCheck = ('{{{emailcheck}}}' == 'true');
|
||||||
|
var features = parseInt('{{{features}}}');
|
||||||
|
var passRequirements = '{{{passRequirements}}}';
|
||||||
|
if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } else { passRequirements = {}; }
|
||||||
|
var passRequirementsEx = ((passRequirements.min != null) || (passRequirements.max != null) || (passRequirements.upper != null) || (passRequirements.lower != null) || (passRequirements.numeric != null) || (passRequirements.nonalpha != null));
|
||||||
|
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
||||||
|
var publicKeyCredentialRequestOptions = null;
|
||||||
|
var currentpanel = 0;
|
||||||
|
|
||||||
|
// Display the right server message
|
||||||
|
var messageid = parseInt('{{{messageid}}}');
|
||||||
|
var okmessages = ['', "Hold on, reset mail sent."];
|
||||||
|
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."];
|
||||||
|
if (messageid > 0) {
|
||||||
|
var msg = '';
|
||||||
|
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
||||||
|
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
||||||
|
if (msg != '') {
|
||||||
|
if (messageid >= 100) { msg = ('<span class="msg error"><b style=color:#8C001A>' + msg + '<b></span><br /><br />'); } else { msg = ('<span class="msg success"><b>' + msg + '</b></span><br /><br />'); }
|
||||||
|
for (var i = 1; i < 7; i++) { QH('message' + i, msg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If URL arguments are provided, add them to form posts
|
||||||
|
if (window.location.href.indexOf('?') > 0) {
|
||||||
|
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
||||||
|
Q('loginformargs').value = urlargs;
|
||||||
|
Q('createformargs').value = urlargs;
|
||||||
|
Q('resetformargs').value = urlargs;
|
||||||
|
Q('tokenformargs').value = urlargs;
|
||||||
|
Q('resettokenformargs').value = urlargs;
|
||||||
|
Q('resetpasswordformargs').value = urlargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function startup() {
|
||||||
|
if ((features & 32) == 0) {
|
||||||
|
// Guard against other site's top frames (web bugs).
|
||||||
|
var loc = null;
|
||||||
|
try { loc = top.location.toString().toLowerCase(); } catch (e) { }
|
||||||
|
if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features & 0x200000) { // Email is username
|
||||||
|
QH('loginusername', "Email:");
|
||||||
|
QH('resetAccountSpan', "Zapomenuté heslo?");
|
||||||
|
QV('nuUserRow', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QV('createPanelHint', passRequirements.hint === true);
|
||||||
|
QV('resetpasswordpanelHint', passRequirements.hint === true);
|
||||||
|
|
||||||
|
window.onresize = center;
|
||||||
|
center();
|
||||||
|
validateLogin();
|
||||||
|
validateCreate();
|
||||||
|
if (loginMode.length != 0) { go(parseInt(loginMode)); } else { go(1); }
|
||||||
|
QV('newAccountDiv', (newAccount === '1') || (newAccount === 'true')); // If new accounts are not allowed, don't display the new account link.
|
||||||
|
if ((passRequirements.hint === true) && (passhint != null) && (passhint.length > 0)) { QV('showPassHintLink', true); }
|
||||||
|
QV('newAccountPass', (newAccountPass == 1));
|
||||||
|
QV('resetAccountDiv', (emailCheck == true));
|
||||||
|
QV('hrAccountDiv', (emailCheck == true) || (newAccountPass == 1));
|
||||||
|
|
||||||
|
if (loginMode == '4') {
|
||||||
|
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||||
|
QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loginMode == '5') {
|
||||||
|
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||||
|
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||||
|
if (typeof hardwareKeyChallenge.challenge == 'string') { hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer; }
|
||||||
|
|
||||||
|
publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
|
||||||
|
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
|
||||||
|
publicKeyCredentialRequestOptions.allowCredentials.push(
|
||||||
|
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New WebAuthn hardware keys
|
||||||
|
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
|
||||||
|
function (rawAssertion) {
|
||||||
|
var assertion = {
|
||||||
|
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
|
||||||
|
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
|
||||||
|
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
|
||||||
|
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
|
||||||
|
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
|
||||||
|
};
|
||||||
|
Q('resetHwtokenInput').value = JSON.stringify(assertion);
|
||||||
|
QE('resetTokenOkButton', true);
|
||||||
|
Q('resetTokenOkButton').click();
|
||||||
|
},
|
||||||
|
function (error) { console.log('credentials-get error', error); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a hardware security key
|
||||||
|
function useSecurityKey() {
|
||||||
|
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||||
|
if (typeof hardwareKeyChallenge.challenge == 'string') { hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer; }
|
||||||
|
|
||||||
|
publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
|
||||||
|
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
|
||||||
|
publicKeyCredentialRequestOptions.allowCredentials.push(
|
||||||
|
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New WebAuthn hardware keys
|
||||||
|
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
|
||||||
|
function (rawAssertion) {
|
||||||
|
var assertion = {
|
||||||
|
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
|
||||||
|
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
|
||||||
|
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
|
||||||
|
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
|
||||||
|
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
|
||||||
|
};
|
||||||
|
Q('hwtokenInput').value = JSON.stringify(assertion);
|
||||||
|
QE('tokenOkButton', true);
|
||||||
|
Q('tokenOkButton').click();
|
||||||
|
},
|
||||||
|
function (error) { console.log('credentials-get error', error); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPassHint() {
|
||||||
|
if (passRequirements.hint === true) { messagebox("Password Hint", passhint); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function xgo(x) {
|
||||||
|
QV('message1', false);
|
||||||
|
QV('message2', false);
|
||||||
|
QV('message3', false);
|
||||||
|
QV('message4', false);
|
||||||
|
QV('message5', false);
|
||||||
|
QV('message6', false);
|
||||||
|
go(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
function go(x) {
|
||||||
|
currentpanel = x;
|
||||||
|
setDialogMode(0);
|
||||||
|
QV('showPassHintLink', false);
|
||||||
|
QV('loginpanel', x == 1);
|
||||||
|
QV('createpanel', x == 2);
|
||||||
|
QV('resetpanel', x == 3);
|
||||||
|
QV('tokenpanel', x == 4);
|
||||||
|
QV('resettokenpanel', x == 5);
|
||||||
|
QV('resetpasswordpanel', x == 6);
|
||||||
|
if (x == 1) { Q('username').focus(); }
|
||||||
|
if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
|
||||||
|
if (x == 3) { Q('remail').focus(); }
|
||||||
|
if (x == 4) { Q('tokenInput').focus(); }
|
||||||
|
if (x == 5) { Q('resetTokenInput').focus(); }
|
||||||
|
if (x == 6) { Q('rapassword1').focus(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateLogin(box, e) {
|
||||||
|
var ok = ((Q('username').value.length > 0) && (Q('username').value.indexOf(' ') == -1) && (Q('password').value.length > 0));
|
||||||
|
QE('loginButton', ok);
|
||||||
|
setDialogMode(0);
|
||||||
|
if ((e != null) && (e.keyCode == 13)) { if (box == 1) { Q('password').focus(); } else if (box == 2) { Q('loginButton').click(); } }
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateCreate(box,e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var ok = false;
|
||||||
|
if (features & 0x200000) { ok = true; } else { ok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1); }
|
||||||
|
ok &= ((validateEmail(Q('aemail').value) == true) && (Q('apassword1').value.length > 0) && (Q('apassword2').value == Q('apassword1').value));
|
||||||
|
if ((newAccountPass == 1) && (Q('anewaccountpass').value.length == 0)) { ok = false; }
|
||||||
|
if (Q('apassword1').value == '') {
|
||||||
|
QH('passWarning', '');
|
||||||
|
QV('passwordPolicyCallout', false);
|
||||||
|
} else {
|
||||||
|
if (!passRequirementsEx) {
|
||||||
|
// No password requirements, display password strength
|
||||||
|
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||||
|
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>' + "Silné heslo" + '</b><span>'); }
|
||||||
|
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>' + "Dobré heslo" + '</b><span>'); }
|
||||||
|
else { QH('passWarning', '<span style=color:red><b>' + "Slabé heslo" + '</b><span>'); }
|
||||||
|
} else {
|
||||||
|
// Password requirements provided, use that
|
||||||
|
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||||||
|
if (passReq == false) {
|
||||||
|
ok = false;
|
||||||
|
//QS('nuPass1').color = '#7b241c';
|
||||||
|
//QS('nuPass2').color = '#7b241c';
|
||||||
|
QH('passWarning', '<span style=color:red><b>' + "Password Policy" + '</b><span>'); // TODO: Display problem hint
|
||||||
|
QV('passwordPolicyCallout', true);
|
||||||
|
QH('passwordPolicyCallout', passwordPolicyText(Q('apassword1').value));
|
||||||
|
} else {
|
||||||
|
QH('passWarning', '');
|
||||||
|
QV('passwordPolicyCallout', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QE('createButton', ok);
|
||||||
|
if ((e != null) && (e.keyCode == 13)) {
|
||||||
|
if (box == 1) { Q('aemail').focus(); }
|
||||||
|
if (box == 2) { Q('apassword1').focus(); }
|
||||||
|
if (box == 3) { Q('apassword2').focus(); }
|
||||||
|
if (box == 4) { Q('apasswordhint').focus(); }
|
||||||
|
if (box == 5) { if (newAccountPass == 1) { Q('anewaccountpass').focus(); } else { Q('createButton').click(); } }
|
||||||
|
if (box == 6) { Q('createButton').click(); }
|
||||||
|
}
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePassReset(box, e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var pass1ok = (Q('rapassword1').value.length > 0);
|
||||||
|
var pass2ok = (Q('rapassword2').value.length > 0) && (Q('rapassword2').value == Q('rapassword1').value);
|
||||||
|
var ok = (pass1ok && pass2ok);
|
||||||
|
|
||||||
|
// Color the fields
|
||||||
|
QS('rnuPass1').color = pass1ok ? 'black' : '#7b241c';
|
||||||
|
QS('rnuPass2').color = pass2ok ? 'black' : '#7b241c';
|
||||||
|
|
||||||
|
if (Q('rapassword1').value == '') {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
} else {
|
||||||
|
if (!passRequirementsEx) {
|
||||||
|
// No password requirements, display password strength
|
||||||
|
var passStrength = checkPasswordStrength(Q('rapassword1').value);
|
||||||
|
if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>' + "Silné heslo" + '</b><span>'); }
|
||||||
|
else if (passStrength >= 60) { QH('rpassWarning', '<span style=color:blue><b>' + "Dobré heslo" + '</b><span>'); }
|
||||||
|
else { QH('rpassWarning', '<span style=color:red><b>' + "Slabé heslo" + '</b><span>'); }
|
||||||
|
} else {
|
||||||
|
// Password requirements provided, use that
|
||||||
|
var passReq = checkPasswordRequirements(Q('rapassword1').value, passRequirements);
|
||||||
|
if (passReq == false) {
|
||||||
|
ok = false;
|
||||||
|
QS('rnuPass1').color = '#7b241c';
|
||||||
|
QS('rnuPass2').color = '#7b241c';
|
||||||
|
QH('rpassWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>' + "Password Policy" + '</b><div>'); // This is also a link to the password policy
|
||||||
|
QV('rpasswordPolicyCallout', true);
|
||||||
|
QH('rpasswordPolicyCallout', passwordPolicyText(Q('rapassword1').value));
|
||||||
|
} else {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((e != null) && (e.keyCode == 13)) {
|
||||||
|
if (box == 2) { Q('rapassword1').focus(); }
|
||||||
|
if (box == 3) { Q('rapassword2').focus(); }
|
||||||
|
if (box == 4) { Q('rapasswordhint').focus(); }
|
||||||
|
if (box == 6) { Q('resetPassButton').click(); }
|
||||||
|
}
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
QE('resetPassButton', ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateReset(e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var x = validateEmail(Q('remail').value);
|
||||||
|
QE('eresetButton', x);
|
||||||
|
if ((e != null) && (e.keyCode == 13) && (x == true)) { Q('eresetButton').click(); }
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function passwordPolicyText(pass) {
|
||||||
|
var policy = '<div style=text-align:left>';
|
||||||
|
var counts = strCount(pass);
|
||||||
|
if (passRequirements.min && ((pass == null) || (pass.length < passRequirements.min))) { policy += format("Minimum length of {0}", passRequirements.min) + '<br />'; }
|
||||||
|
if (passRequirements.max && ((pass == null) || (pass.length > passRequirements.max))) { policy += format("Maximum length of {0}", passRequirements.max) + '<br />'; }
|
||||||
|
if (passRequirements.upper && ((pass == null) || (counts.upper < passRequirements.upper))) { policy += format("{0} upper case", passRequirements.upper) + '<br />'; }
|
||||||
|
if (passRequirements.lower && ((pass == null) || (counts.lower < passRequirements.lower))) { policy += format("{0} lower case", passRequirements.lower) + '<br />'; }
|
||||||
|
if (passRequirements.numeric && ((pass == null) || (counts.numeric < passRequirements.numeric))) { policy += format("{0} numeric", passRequirements.numeric) + '<br />'; }
|
||||||
|
if (passRequirements.nonalpha && ((pass == null) || (counts.nonalpha < passRequirements.nonalpha))) { policy += format("{0} non-alphanumeric", passRequirements.nonalpha) + '<br />'; }
|
||||||
|
policy += '</div>';
|
||||||
|
return policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a password strength score
|
||||||
|
function checkPasswordStrength(password) {
|
||||||
|
var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
|
||||||
|
if (!password) return 0;
|
||||||
|
for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
|
||||||
|
for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
|
||||||
|
return parseInt(r + (varCount - 1) * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check password requirements
|
||||||
|
function checkPasswordRequirements(password, requirements) {
|
||||||
|
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||||||
|
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||||||
|
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||||||
|
var counts = strCount(password);
|
||||||
|
if (requirements.numeric && (counts.numeric < requirements.numeric)) return false;
|
||||||
|
if (requirements.lower && (counts.lower < requirements.lower)) return false;
|
||||||
|
if (requirements.upper && (counts.upper < requirements.upper)) return false;
|
||||||
|
if (requirements.nonalpha && (counts.nonalpha < requirements.nonalpha)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function strCount(password) {
|
||||||
|
var counts = { numeric: 0, lower: 0, upper: 0, nonalpha: 0 };
|
||||||
|
if (typeof password != 'string') return counts;
|
||||||
|
for (var i = 0; i < password.length; i++) {
|
||||||
|
if (/\d/.test(password[i])) { counts.numeric++; }
|
||||||
|
if (/[a-z]/.test(password[i])) { counts.lower++; }
|
||||||
|
if (/[A-Z]/.test(password[i])) { counts.upper++; }
|
||||||
|
if (/\W/.test(password[i])) { counts.nonalpha++; }
|
||||||
|
}
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xcheckTokenTimer = null;
|
||||||
|
function checkTokenTimer(enter) {
|
||||||
|
if ((enter == 0) && (xcheckTokenTimer != null)) { clearInterval(xcheckTokenTimer); xcheckTokenTimer = null; }
|
||||||
|
if ((enter == 1) && (xcheckTokenTimer == null)) { xcheckTokenTimer = setInterval(checkToken, 200); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkToken() {
|
||||||
|
var t1 = Q('tokenInput').value, t2 = t1.split(' ').join('');
|
||||||
|
if (t1 != t2) { Q('tokenInput').value = t2; }
|
||||||
|
QE('tokenOkButton', (Q('tokenInput').value.length == 6) || (Q('tokenInput').value.length == 8) || (Q('tokenInput').value.length == 44));
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetCheckToken() {
|
||||||
|
var t1 = Q('resetTokenInput').value, t2 = t1.split(' ').join('');
|
||||||
|
if (t1 != t2) { Q('resetTokenInput').value = t2; }
|
||||||
|
QE('resetTokenOkButton', (Q('resetTokenInput').value.length == 6) || (Q('resetTokenInput').value.length == 8) || (Q('resetTokenInput').value.length == 44));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POPUP DIALOG
|
||||||
|
//
|
||||||
|
|
||||||
|
// undefined = Hidden, 1 = Generic Message
|
||||||
|
var xxdialogMode;
|
||||||
|
var xxdialogFunc;
|
||||||
|
var xxdialogButtons;
|
||||||
|
var xxdialogTag;
|
||||||
|
var xxcurrentView = 0;
|
||||||
|
|
||||||
|
// Display a dialog box
|
||||||
|
// Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
|
||||||
|
function setDialogMode(x, y, b, f, c, tag) {
|
||||||
|
xxdialogMode = x;
|
||||||
|
xxdialogFunc = f;
|
||||||
|
xxdialogButtons = b;
|
||||||
|
xxdialogTag = tag;
|
||||||
|
QE('idx_dlgOkButton', true);
|
||||||
|
QV('idx_dlgOkButton', b & 1);
|
||||||
|
QV('idx_dlgCancelButton', b & 2);
|
||||||
|
QV('id_dialogclose', (b & 2) || (b & 8));
|
||||||
|
QV('idx_dlgButtonBar', b & 7);
|
||||||
|
if (y) QH('id_dialogtitle', y);
|
||||||
|
for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
|
||||||
|
QV('dialog', x);
|
||||||
|
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
|
||||||
|
}
|
||||||
|
|
||||||
|
function dialogclose(x) {
|
||||||
|
var f = xxdialogFunc;
|
||||||
|
var b = xxdialogButtons;
|
||||||
|
var t = xxdialogTag;
|
||||||
|
setDialogMode();
|
||||||
|
if (((b & 8) || x) && f) f(x, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
function center() { QS('dialog').left = ((((getDocWidth() - 400) / 2)) + 'px'); }
|
||||||
|
function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
|
||||||
|
function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
|
||||||
|
function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
|
||||||
|
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
|
function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
|
||||||
|
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
|
||||||
|
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body></html>
|
725
views/translations/login_cs.handlebars
Normal file
725
views/translations/login_cs.handlebars
Normal file
@ -0,0 +1,725 @@
|
|||||||
|
<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link rel="shortcut icon" type="image/x-icon" href="{{{domainurl}}}favicon.ico">
|
||||||
|
<link keeplink="1" type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||||
|
<script keeplink="1" type="text/javascript" src="scripts/u2f-api.js"></script>
|
||||||
|
<title>{{{title}}} - Login</title>
|
||||||
|
</head>
|
||||||
|
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" class="arg_hide login">
|
||||||
|
<div id="container">
|
||||||
|
<div id="masthead">
|
||||||
|
<div class="title">{{{title}}}</div>
|
||||||
|
<div class="title2">{{{title2}}}</div>
|
||||||
|
</div>
|
||||||
|
<div id="topbar" class="noselect style3" style="height:24px">
|
||||||
|
<div id="uiMenuButton" title="User interface selection" onclick="showUserInterfaceSelectMenu()">
|
||||||
|
♦
|
||||||
|
<div id="uiMenu" style="display:none">
|
||||||
|
<div id="uiViewButton1" class="uiSelector" onclick="userInterfaceSelectMenu(1)" title="Left bar interface"><div class="uiSelector1"></div></div>
|
||||||
|
<div id="uiViewButton2" class="uiSelector" onclick="userInterfaceSelectMenu(2)" title="Top bar interface"><div class="uiSelector2"></div></div>
|
||||||
|
<div id="uiViewButton3" class="uiSelector" onclick="userInterfaceSelectMenu(3)" title="Fixed width interface"><div class="uiSelector3"></div></div>
|
||||||
|
<div id="uiViewButton4" class="uiSelector" onclick="toggleNightMode()" title="Toggle night mode"><div class="uiSelector4"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="column_l">
|
||||||
|
<h1>Vítejte</h1>
|
||||||
|
<div id="welcomeText" style="display:none">Přihlašte se na různá svá nebo firemní zařízení odkudkoliv z celého světa <a href="http://www.meshcommander.com/meshcentral2">MeshCentral</a>. Jednoduchá správa přes web. Jediné co potřebujete je agent na daném zařízení. Po instalaci uvidíte zařízení v sekci "Moje zařízení" a můžete toto zařízení ovládat.</div>
|
||||||
|
<table id="centralTable" style="">
|
||||||
|
<tbody><tr>
|
||||||
|
<td id="welcomeimage">
|
||||||
|
<picture>
|
||||||
|
<img alt="" src="welcome.jpg" style="border-radius:20px">
|
||||||
|
</picture>
|
||||||
|
</td>
|
||||||
|
<td id="logincell">
|
||||||
|
<div id="loginpanel" style="display:none">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="login">
|
||||||
|
<div id="message1"></div>
|
||||||
|
<div>
|
||||||
|
<b>Přihlásit</b>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td id="loginusername" align="right" width="100">Uživatel:</td>
|
||||||
|
<td><input id="username" type="text" maxlength="64" name="username" onchange="validateLogin(1)" onkeyup="validateLogin(1,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="right">Heslo:</td>
|
||||||
|
<td><input id="password" type="password" maxlength="256" name="password" autocomplete="off" onchange="validateLogin(2)" onkeyup="validateLogin(2,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><div id="showPassHintLink" style="display:none"><a onclick="return showPassHint(event);" href="#" style="cursor:pointer">Show Hint</a></div></td>
|
||||||
|
<td align="right"><input id="loginButton" type="submit" value="Přihlásit" disabled="disabled"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<div id="hrAccountDiv" style="display:none"><hr></div>
|
||||||
|
<div id="resetAccountDiv" style="display:none;padding:2px">
|
||||||
|
<span id="resetAccountSpan">Forgot username/password?</span> <a onclick="return xgo(3,event);" href="#" style="cursor:pointer">Reset účtu</a>.
|
||||||
|
</div>
|
||||||
|
<div id="newAccountDiv" style="display:none;padding:2px">
|
||||||
|
Nemáte účet? <a onclick="return xgo(2,event);" href="#" style="cursor:pointer">Vytvořit</a>.
|
||||||
|
</div>
|
||||||
|
<input id="loginformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="createpanel" style="display:none;position:relative">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="createaccount">
|
||||||
|
<div id="message2"></div>
|
||||||
|
<div>
|
||||||
|
<b>Account Creation</b>
|
||||||
|
</div>
|
||||||
|
<div id="passwordPolicyCallout" style="display:none"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr id="nuUserRow">
|
||||||
|
<td id="nuUser" align="right" width="100">Uživatel:</td>
|
||||||
|
<td><input id="ausername" type="text" name="username" onchange="validateCreate(1)" maxlength="64" onkeydown="haltReturn(event)" onkeyup="validateCreate(1,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="nuEmail" align="right" width="100">Email:</td>
|
||||||
|
<td><input id="aemail" type="text" name="email" onchange="validateCreate(2)" maxlength="256" onkeydown="haltReturn(event)" onkeyup="validateCreate(2,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="nuPass1" align="right">Heslo:</td>
|
||||||
|
<td><input id="apassword1" type="password" name="password1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(3,event)" onkeyup="validateCreate(3,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="nuPass2" align="right">Heslo:</td>
|
||||||
|
<td><input id="apassword2" type="password" name="password2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(4,event)" onkeyup="validateCreate(4,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="createPanelHint" style="display:none">
|
||||||
|
<td id="nuHint" align="right">Password Hint:</td>
|
||||||
|
<td><input id="apasswordhint" type="text" name="apasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(5,event)" onkeyup="validateCreate(5,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="newAccountPass" title="Enter the account creation token">
|
||||||
|
<td id="nuToken" align="right">Creation Token:</td>
|
||||||
|
<td><input id="anewaccountpass" type="password" name="anewaccountpass" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validateCreate(6,event)" onkeyup="validateCreate(6,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="createButton" type="submit" value="Create Account" disabled="disabled"></div>
|
||||||
|
<div id="passWarning" style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="createformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="resetpanel" style="display:none">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
|
<div id="message3"></div>
|
||||||
|
<div>
|
||||||
|
<b>Reset hesla</b>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="right" width="100">Email:</td>
|
||||||
|
<td><input id="remail" type="text" name="email" maxlength="256" onchange="validateReset()" onkeyup="validateReset(event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="eresetButton" type="submit" value="Reset účtu" disabled="disabled"></div>
|
||||||
|
<div id="passWarning" style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="resetformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="tokenpanel" style="display:none">
|
||||||
|
<form method="post" autocomplete="off">
|
||||||
|
<input type="hidden" name="action" value="tokenlogin">
|
||||||
|
<input type="hidden" name="hwstate" value="{{{hwstate}}}">
|
||||||
|
<div id="message4"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="right" width="100">Login token:</td>
|
||||||
|
<td>
|
||||||
|
<input id="tokenInput" type="text" name="token" maxlength="50" onchange="checkToken(event)" onpaste="resetCheckToken(event)" onkeyup="checkToken(event)" onkeydown="checkToken(event)"><br>
|
||||||
|
<input id="hwtokenInput" type="text" name="hwtoken" style="display:none">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="align-content:center">
|
||||||
|
<label><input id="tokenInputRemember" name="remembertoken" type="checkbox">Remember this device for 30 days.</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="tokenOkButton" type="submit" value="Login" disabled="disabled"></div>
|
||||||
|
<div style="float:right"><input style="display:none;float:right" id="securityKeyButton" type="button" value="Use Security Key" onclick="useSecurityKey()"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="tokenformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="resettokenpanel" style="display:none">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="resetaccount">
|
||||||
|
<div id="message5"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="right" width="100">Login token:</td>
|
||||||
|
<td>
|
||||||
|
<input id="resetTokenInput" type="text" name="token" maxlength="50" onchange="resetCheckToken(event)" onkeyup="resetCheckToken(event)" onkeydown="resetCheckToken(event)">
|
||||||
|
<input id="resetHwtokenInput" type="text" name="hwtoken" style="display:none">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="resetTokenOkButton" type="submit" value="Login" disabled="disabled"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="resettokenformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="resetpasswordpanel" style="display:none;position:relative">
|
||||||
|
<form method="post">
|
||||||
|
<input type="hidden" name="action" value="resetpassword">
|
||||||
|
<div id="message6"></div>
|
||||||
|
<div id="rpasswordPolicyCallout" style="display:none"></div>
|
||||||
|
<table>
|
||||||
|
<tbody><tr>
|
||||||
|
<td id="rnuPass1" width="100" align="right">Heslo:</td>
|
||||||
|
<td><input id="rapassword1" type="password" name="rpassword1" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(3,event)" onkeyup="validatePassReset(3,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td id="rnuPass2" align="right">Heslo:</td>
|
||||||
|
<td><input id="rapassword2" type="password" name="rpassword2" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(4,event)" onkeyup="validatePassReset(4,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr id="resetpasswordpanelHint" style="display:none">
|
||||||
|
<td id="rnuHint" align="right">Password Hint:</td>
|
||||||
|
<td><input id="rapasswordhint" type="text" name="rpasswordhint" autocomplete="off" maxlength="256" onkeydown="haltReturn(event)" onchange="validatePassReset(5,event)" onkeyup="validatePassReset(5,event)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">
|
||||||
|
<div style="float:right"><input id="resetPassButton" type="submit" value="Reset hesla" disabled="disabled"></div>
|
||||||
|
<div id="rpassWarning" style="padding-top:6px"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<hr><a onclick="return xgo(1,event);" href="#" style="cursor:pointer">Back to login</a>
|
||||||
|
<input id="resetpasswordformargs" name="urlargs" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<div class="footer1">{{{footer}}}</div>
|
||||||
|
<div class="footer2">
|
||||||
|
{{{rootCertLink}}}
|
||||||
|
<a href="terms">Terms & Privacy</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="dialog" style="display:none">
|
||||||
|
<div id="dialogHeader">
|
||||||
|
<div id="id_dialogclose" style="float:right;padding:5px;cursor:pointer" onclick="setDialogMode()"><b>X</b></div>
|
||||||
|
<div id="id_dialogtitle" style="padding:5px"></div>
|
||||||
|
<div style="width:100%;margin:6px"></div>
|
||||||
|
</div>
|
||||||
|
<div id="dialogBody">
|
||||||
|
<div id="dialog1">
|
||||||
|
<div id="id_dialogMessage" style=""></div>
|
||||||
|
</div>
|
||||||
|
<div id="dialog2" style="">
|
||||||
|
<div id="id_dialogOptions"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="idx_dlgButtonBar" style="">
|
||||||
|
<input id="idx_dlgCancelButton" type="button" value="Zrušit" style="" onclick="dialogclose(0)">
|
||||||
|
<input id="idx_dlgOkButton" type="button" value="OK" style="" onclick="dialogclose(1)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
var passhint = '{{{passhint}}}';
|
||||||
|
var loginMode = '{{{loginmode}}}';
|
||||||
|
var newAccount = '{{{newAccount}}}';
|
||||||
|
var newAccountPass = parseInt('{{{newAccountPass}}}');
|
||||||
|
var emailCheck = ('{{{emailcheck}}}' == 'true');
|
||||||
|
var passRequirements = '{{{passRequirements}}}';
|
||||||
|
var hardwareKeyChallenge = decodeURIComponent('{{{hkey}}}');
|
||||||
|
if (passRequirements != '') { passRequirements = JSON.parse(decodeURIComponent(passRequirements)); } else { passRequirements = {}; }
|
||||||
|
var passRequirementsEx = ((passRequirements.min != null) || (passRequirements.max != null) || (passRequirements.upper != null) || (passRequirements.lower != null) || (passRequirements.numeric != null) || (passRequirements.nonalpha != null));
|
||||||
|
var features = parseInt('{{{features}}}');
|
||||||
|
var welcomeText = decodeURIComponent('{{{welcometext}}}');
|
||||||
|
var currentpanel = 0;
|
||||||
|
var uiMode = parseInt(getstore('uiMode', '1'));
|
||||||
|
var webPageFullScreen = true;
|
||||||
|
var nightMode = (getstore('_nightMode', '0') == '1');
|
||||||
|
var publicKeyCredentialRequestOptions = null;
|
||||||
|
|
||||||
|
// Display the right server message
|
||||||
|
var messageid = parseInt('{{{messageid}}}');
|
||||||
|
var okmessages = ['', "Hold on, reset mail sent."];
|
||||||
|
var failmessages = ["Unable to create account.", "Account limit reached.", "Existing account with this email address.", "Invalid account creation token.", "Username already exists.", "Password rejected, use a different one.", "Invalid email.", "Account not found.", "Invalid token, try again.", "Unable to sent email.", "Account locked.", "Access denied.", "Login failed, check username and password.", "Password change requested.", "IP address blocked, try again later."];
|
||||||
|
if (messageid > 0) {
|
||||||
|
var msg = '';
|
||||||
|
if ((messageid < 100) && (messageid < okmessages.length)) { msg = okmessages[messageid]; }
|
||||||
|
else if ((messageid >= 100) && ((messageid - 100) < failmessages.length)) { msg = failmessages[messageid - 100]; }
|
||||||
|
if (msg != '') {
|
||||||
|
if (messageid >= 100) { msg = ('<span class="msg error"><b style=color:#8C001A>' + msg + '<b></span><br /><br />'); } else { msg = ('<span class="msg success"><b>' + msg + '</b></span><br /><br />'); }
|
||||||
|
for (var i = 1; i < 7; i++) { QH('message' + i, msg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If URL arguments are provided, add them to form posts
|
||||||
|
if (window.location.href.indexOf('?') > 0) {
|
||||||
|
var urlargs = window.location.href.substring(window.location.href.indexOf('?'));
|
||||||
|
Q('loginformargs').value = urlargs;
|
||||||
|
Q('createformargs').value = urlargs;
|
||||||
|
Q('resetformargs').value = urlargs;
|
||||||
|
Q('tokenformargs').value = urlargs;
|
||||||
|
Q('resettokenformargs').value = urlargs;
|
||||||
|
Q('resetpasswordformargs').value = urlargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//var webPageFullScreen = getstore('webPageFullScreen', true);
|
||||||
|
//if (webPageFullScreen == 'false') { webPageFullScreen = false; }
|
||||||
|
//if (webPageFullScreen == 'true') { webPageFullScreen = true; }
|
||||||
|
//toggleFullScreen();
|
||||||
|
|
||||||
|
function startup() {
|
||||||
|
if ((features & 32) == 0) {
|
||||||
|
// Guard against other site's top frames (web bugs).
|
||||||
|
var loc = null;
|
||||||
|
try { loc = top.location.toString().toLowerCase(); } catch (e) { }
|
||||||
|
if (top != self && (loc == null || top.active == false)) { top.location = self.location; return; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features & 0x200000) { // Email is username
|
||||||
|
QH('loginusername', "Email:");
|
||||||
|
QH('resetAccountSpan', "Zapomenuté heslo?");
|
||||||
|
QV('nuUserRow', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nightMode) { QC('body').add('night'); }
|
||||||
|
|
||||||
|
QV('createPanelHint', passRequirements.hint === true);
|
||||||
|
QV('resetpasswordpanelHint', passRequirements.hint === true);
|
||||||
|
|
||||||
|
// Display the welcome text
|
||||||
|
if (welcomeText) { QH('welcomeText', welcomeText); }
|
||||||
|
QV('welcomeText', true);
|
||||||
|
|
||||||
|
window.onresize = center;
|
||||||
|
center();
|
||||||
|
|
||||||
|
validateLogin();
|
||||||
|
validateCreate();
|
||||||
|
if (loginMode.length != 0) { go(parseInt(loginMode)); } else { go(1); }
|
||||||
|
QV('newAccountDiv', (newAccount === '1') || (newAccount === 'true')); // If new accounts are not allowed, don't display the new account link.
|
||||||
|
if ((passhint != null) && (passhint.length > 0)) { QV('showPassHintLink', true); }
|
||||||
|
QV('newAccountPass', (newAccountPass == 1));
|
||||||
|
QV('resetAccountDiv', (emailCheck == true));
|
||||||
|
QV('hrAccountDiv', (emailCheck == true) || (newAccountPass == 1));
|
||||||
|
|
||||||
|
if (loginMode == '4') {
|
||||||
|
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||||
|
QV('securityKeyButton', (hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loginMode == '5') {
|
||||||
|
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
|
||||||
|
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||||
|
if (typeof hardwareKeyChallenge.challenge == 'string') { hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer; }
|
||||||
|
|
||||||
|
publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
|
||||||
|
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
|
||||||
|
publicKeyCredentialRequestOptions.allowCredentials.push(
|
||||||
|
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New WebAuthn hardware keys
|
||||||
|
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
|
||||||
|
function (rawAssertion) {
|
||||||
|
var assertion = {
|
||||||
|
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
|
||||||
|
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
|
||||||
|
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
|
||||||
|
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
|
||||||
|
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
|
||||||
|
};
|
||||||
|
Q('resetHwtokenInput').value = JSON.stringify(assertion);
|
||||||
|
QE('resetTokenOkButton', true);
|
||||||
|
Q('resetTokenOkButton').click();
|
||||||
|
},
|
||||||
|
function (error) { console.log('credentials-get error', error); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the user interface in the right mode
|
||||||
|
userInterfaceSelectMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a hardware security key
|
||||||
|
function useSecurityKey() {
|
||||||
|
if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
|
||||||
|
if (typeof hardwareKeyChallenge.challenge == 'string') { hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), function (c) { return c.charCodeAt(0) }).buffer; }
|
||||||
|
|
||||||
|
publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
|
||||||
|
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
|
||||||
|
publicKeyCredentialRequestOptions.allowCredentials.push(
|
||||||
|
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), function (c) { return c.charCodeAt(0) }), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New WebAuthn hardware keys
|
||||||
|
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
|
||||||
|
function (rawAssertion) {
|
||||||
|
var assertion = {
|
||||||
|
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
|
||||||
|
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
|
||||||
|
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
|
||||||
|
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
|
||||||
|
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
|
||||||
|
};
|
||||||
|
Q('hwtokenInput').value = JSON.stringify(assertion);
|
||||||
|
QE('tokenOkButton', true);
|
||||||
|
Q('tokenOkButton').click();
|
||||||
|
},
|
||||||
|
function (error) { console.log('credentials-get error', error); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPassHint(e) {
|
||||||
|
messagebox("Password Hint", passhint);
|
||||||
|
haltEvent(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function xgo(x, e) {
|
||||||
|
QV('message1', false);
|
||||||
|
QV('message2', false);
|
||||||
|
QV('message3', false);
|
||||||
|
QV('message4', false);
|
||||||
|
QV('message5', false);
|
||||||
|
QV('message6', false);
|
||||||
|
go(x);
|
||||||
|
haltEvent(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function go(x) {
|
||||||
|
currentpanel = x;
|
||||||
|
setDialogMode(0);
|
||||||
|
QV('showPassHintLink', false);
|
||||||
|
QV('loginpanel', x == 1);
|
||||||
|
QV('createpanel', x == 2);
|
||||||
|
QV('resetpanel', x == 3);
|
||||||
|
QV('tokenpanel', x == 4);
|
||||||
|
QV('resettokenpanel', x == 5);
|
||||||
|
QV('resetpasswordpanel', x == 6);
|
||||||
|
if (x == 1) { Q('username').focus(); }
|
||||||
|
if (x == 2) { if (features & 0x200000) { Q('aemail').focus(); } else { Q('ausername').focus(); } } // Email is username
|
||||||
|
if (x == 3) { Q('remail').focus(); }
|
||||||
|
if (x == 4) { Q('tokenInput').focus(); }
|
||||||
|
if (x == 5) { Q('resetTokenInput').focus(); }
|
||||||
|
if (x == 6) { Q('rapassword1').focus(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateLogin(box, e) {
|
||||||
|
var ok = ((Q('username').value.length > 0) && (Q('username').value.indexOf(' ') == -1) && (Q('password').value.length > 0));
|
||||||
|
QE('loginButton', ok);
|
||||||
|
setDialogMode(0);
|
||||||
|
if ((e != null) && (e.keyCode == 13)) { if ((box == 1) && (Q('username').value != '')) { Q('password').focus(); } else if ((box == 2) && (Q('password').value != '')) { Q('loginButton').click(); } }
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateCreate(box, e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var userok = false;
|
||||||
|
if (features & 0x200000) { userok = true; } else { userok = (Q('ausername').value.length > 0) && (Q('ausername').value.indexOf(' ') == -1) && (Q('ausername').value.indexOf('"') == -1) && (Q('ausername').value.indexOf(',') == -1); }
|
||||||
|
var emailok = (validateEmail(Q('aemail').value) == true);
|
||||||
|
var pass1ok = (Q('apassword1').value.length > 0);
|
||||||
|
var pass2ok = (Q('apassword2').value.length > 0) && (Q('apassword2').value == Q('apassword1').value);
|
||||||
|
var newAccOk = (newAccountPass == 0) || (Q('anewaccountpass').value.length > 0);
|
||||||
|
var ok = (userok && emailok && pass1ok && pass2ok && newAccOk);
|
||||||
|
|
||||||
|
// Color the fields
|
||||||
|
QS('nuUser').color = userok?'black':'#7b241c';
|
||||||
|
QS('nuEmail').color = emailok?'black':'#7b241c';
|
||||||
|
QS('nuPass1').color = pass1ok?'black':'#7b241c';
|
||||||
|
QS('nuPass2').color = pass2ok?'black':'#7b241c';
|
||||||
|
QS('nuToken').color = newAccOk?'black':'#7b241c';
|
||||||
|
|
||||||
|
if (Q('apassword1').value == '') {
|
||||||
|
QH('passWarning', '');
|
||||||
|
QV('passwordPolicyCallout', false);
|
||||||
|
} else {
|
||||||
|
if (!passRequirementsEx) {
|
||||||
|
// No password requirements, display password strength
|
||||||
|
var passStrength = checkPasswordStrength(Q('apassword1').value);
|
||||||
|
if (passStrength >= 80) { QH('passWarning', '<span style=color:green><b>' + "Silné heslo" + '</b><span>'); }
|
||||||
|
else if (passStrength >= 60) { QH('passWarning', '<span style=color:blue><b>' + "Dobré heslo" + '</b><span>'); }
|
||||||
|
else { QH('passWarning', '<span style=color:red><b>' + "Slabé heslo" + '</b><span>'); }
|
||||||
|
} else {
|
||||||
|
// Password requirements provided, use that
|
||||||
|
var passReq = checkPasswordRequirements(Q('apassword1').value, passRequirements);
|
||||||
|
if (passReq == false) {
|
||||||
|
ok = false;
|
||||||
|
QS('nuPass1').color = '#7b241c';
|
||||||
|
QS('nuPass2').color = '#7b241c';
|
||||||
|
QH('passWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>' + "Password Policy" + '</b><div>'); // This is also a link to the password policy
|
||||||
|
QV('passwordPolicyCallout', true);
|
||||||
|
QH('passwordPolicyCallout', passwordPolicyText(Q('apassword1').value));
|
||||||
|
} else {
|
||||||
|
QH('passWarning', '');
|
||||||
|
QV('passwordPolicyCallout', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((e != null) && (e.keyCode == 13)) {
|
||||||
|
|
||||||
|
if ((box == 1) && userok) { Q('aemail').focus(); }
|
||||||
|
if ((box == 2) && emailok) { Q('apassword1').focus(); }
|
||||||
|
if ((box == 3) && pass1ok) { Q('apassword2').focus(); }
|
||||||
|
if ((box == 4) && pass2ok) { if (passRequirements.hint === true) { Q('apasswordhint').focus(); } else { box = 5; } }
|
||||||
|
if (box == 5) { if (newAccountPass == 1) { Q('anewaccountpass').focus(); } else { box = 6; } }
|
||||||
|
if (box == 6) { Q('createButton').click(); }
|
||||||
|
}
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
QE('createButton', ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
function validatePassReset(box, e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var pass1ok = (Q('rapassword1').value.length > 0);
|
||||||
|
var pass2ok = (Q('rapassword2').value.length > 0) && (Q('rapassword2').value == Q('rapassword1').value);
|
||||||
|
var ok = (pass1ok && pass2ok);
|
||||||
|
|
||||||
|
// Color the fields
|
||||||
|
QS('rnuPass1').color = pass1ok ? 'black' : '#7b241c';
|
||||||
|
QS('rnuPass2').color = pass2ok ? 'black' : '#7b241c';
|
||||||
|
|
||||||
|
if (Q('rapassword1').value == '') {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
} else {
|
||||||
|
if (!passRequirementsEx) {
|
||||||
|
// No password requirements, display password strength
|
||||||
|
var passStrength = checkPasswordStrength(Q('rapassword1').value);
|
||||||
|
if (passStrength >= 80) { QH('rpassWarning', '<span style=color:green><b>' + "Silné heslo" + '</b><span>'); }
|
||||||
|
else if (passStrength >= 60) { QH('rpassWarning', '<span style=color:blue><b>' + "Dobré heslo" + '</b><span>'); }
|
||||||
|
else { QH('rpassWarning', '<span style=color:red><b>' + "Slabé heslo" + '</b><span>'); }
|
||||||
|
} else {
|
||||||
|
// Password requirements provided, use that
|
||||||
|
var passReq = checkPasswordRequirements(Q('rapassword1').value, passRequirements);
|
||||||
|
if (passReq == false) {
|
||||||
|
ok = false;
|
||||||
|
QS('rnuPass1').color = '#7b241c';
|
||||||
|
QS('rnuPass2').color = '#7b241c';
|
||||||
|
QH('rpassWarning', '<div style=color:red;cursor:pointer onclick=showPasswordPolicy()><b>' + "Password Policy" + '</b><div>'); // This is also a link to the password policy
|
||||||
|
QV('rpasswordPolicyCallout', true);
|
||||||
|
QH('rpasswordPolicyCallout', passwordPolicyText(Q('rapassword1').value));
|
||||||
|
} else {
|
||||||
|
QH('rpassWarning', '');
|
||||||
|
QV('rpasswordPolicyCallout', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((e != null) && (e.keyCode == 13)) {
|
||||||
|
if (box == 2) { Q('rapassword1').focus(); }
|
||||||
|
if (box == 3) { Q('rapassword2').focus(); }
|
||||||
|
if (box == 4) { Q('rapasswordhint').focus(); }
|
||||||
|
if (box == 6) { Q('resetPassButton').click(); }
|
||||||
|
}
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
QE('resetPassButton', ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
function passwordPolicyText(pass) {
|
||||||
|
var policy = '<div style=text-align:left>';
|
||||||
|
var counts = strCount(pass);
|
||||||
|
if (passRequirements.min && ((pass == null) || (pass.length < passRequirements.min))) { policy += format("Minimum length of {0}", passRequirements.min) + '<br />'; }
|
||||||
|
if (passRequirements.max && ((pass == null) || (pass.length > passRequirements.max))) { policy += format("Maximum length of {0}", passRequirements.max) + '<br />'; }
|
||||||
|
if (passRequirements.upper && ((pass == null) || (counts.upper < passRequirements.upper))) { policy += format("{0} upper case", passRequirements.upper) + '<br />'; }
|
||||||
|
if (passRequirements.lower && ((pass == null) || (counts.lower < passRequirements.lower))) { policy += format("{0} lower case", passRequirements.lower) + '<br />'; }
|
||||||
|
if (passRequirements.numeric && ((pass == null) || (counts.numeric < passRequirements.numeric))) { policy += format("{0} numeric", passRequirements.numeric) + '<br />'; }
|
||||||
|
if (passRequirements.nonalpha && ((pass == null) || (counts.nonalpha < passRequirements.nonalpha))) { policy += format("{0} non-alphanumeric", passRequirements.nonalpha) + '<br />'; }
|
||||||
|
policy += '</div>';
|
||||||
|
return policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPasswordPolicy() {
|
||||||
|
messagebox("Password Policy", passwordPolicyText());
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateReset(e) {
|
||||||
|
setDialogMode(0);
|
||||||
|
var x = validateEmail(Q('remail').value);
|
||||||
|
QE('eresetButton', x);
|
||||||
|
if ((e != null) && (e.keyCode == 13) && (x == true)) {
|
||||||
|
Q('eresetButton').click();
|
||||||
|
}
|
||||||
|
if (e != null) { haltEvent(e); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a password strength score
|
||||||
|
function checkPasswordStrength(password) {
|
||||||
|
var r = 0, letters = {}, varCount = 0, variations = { digits: /\d/.test(password), lower: /[a-z]/.test(password), upper: /[A-Z]/.test(password), nonWords: /\W/.test(password) }
|
||||||
|
if (!password) return 0;
|
||||||
|
for (var i = 0; i< password.length; i++) { letters[password[i]] = (letters[password[i]] || 0) + 1; r += 5.0 / letters[password[i]]; }
|
||||||
|
for (var c in variations) { varCount += (variations[c] == true) ? 1 : 0; }
|
||||||
|
return parseInt(r + (varCount - 1) * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check password requirements
|
||||||
|
function checkPasswordRequirements(password, requirements) {
|
||||||
|
if ((requirements == null) || (requirements == '') || (typeof requirements != 'object')) return true;
|
||||||
|
if (requirements.min) { if (password.length < requirements.min) return false; }
|
||||||
|
if (requirements.max) { if (password.length > requirements.max) return false; }
|
||||||
|
var counts = strCount(password);
|
||||||
|
if (requirements.numeric && (counts.numeric < requirements.numeric)) return false;
|
||||||
|
if (requirements.lower && (counts.lower < requirements.lower)) return false;
|
||||||
|
if (requirements.upper && (counts.upper < requirements.upper)) return false;
|
||||||
|
if (requirements.nonalpha && (counts.nonalpha < requirements.nonalpha)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function strCount(password) {
|
||||||
|
var counts = { numeric: 0, lower: 0, upper: 0, nonalpha: 0 };
|
||||||
|
if (typeof password != 'string') return counts;
|
||||||
|
for (var i = 0; i < password.length; i++) {
|
||||||
|
if (/\d/.test(password[i])) { counts.numeric++; }
|
||||||
|
if (/[a-z]/.test(password[i])) { counts.lower++; }
|
||||||
|
if (/[A-Z]/.test(password[i])) { counts.upper++; }
|
||||||
|
if (/\W/.test(password[i])) { counts.nonalpha++; }
|
||||||
|
}
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkToken() {
|
||||||
|
var t1 = Q('tokenInput').value;
|
||||||
|
var t2 = t1.split(' ').join('');
|
||||||
|
if (t1 != t2) { Q('tokenInput').value = t2; }
|
||||||
|
QE('tokenOkButton', (Q('tokenInput').value.length == 6) || (Q('tokenInput').value.length == 8) || (Q('tokenInput').value.length == 44));
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetCheckToken() {
|
||||||
|
var t1 = Q('resetTokenInput').value;
|
||||||
|
var t2 = t1.split(' ').join('');
|
||||||
|
if (t1 != t2) { Q('resetTokenInput').value = t2; }
|
||||||
|
QE('resetTokenOkButton', (Q('resetTokenInput').value.length == 6) || (Q('resetTokenInput').value.length == 8) || (Q('resetTokenInput').value.length == 44));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// POPUP DIALOG
|
||||||
|
//
|
||||||
|
|
||||||
|
// undefined = Hidden, 1 = Generic Message
|
||||||
|
var xxdialogMode;
|
||||||
|
var xxdialogFunc;
|
||||||
|
var xxdialogButtons;
|
||||||
|
var xxdialogTag;
|
||||||
|
var xxcurrentView = 0;
|
||||||
|
|
||||||
|
// Display a dialog box
|
||||||
|
// Parameters: Dialog Mode (0 = none), Dialog Title, Buttons (1 = OK, 2 = Cancel, 3 = OK & Cancel), Call back function(0 = Cancel, 1 = OK), Dialog Content (Mode 2 only)
|
||||||
|
function setDialogMode(x, y, b, f, c, tag) {
|
||||||
|
xxdialogMode = x;
|
||||||
|
xxdialogFunc = f;
|
||||||
|
xxdialogButtons = b;
|
||||||
|
xxdialogTag = tag;
|
||||||
|
QE('idx_dlgOkButton', true);
|
||||||
|
QV('idx_dlgOkButton', b & 1);
|
||||||
|
QV('idx_dlgCancelButton', b & 2);
|
||||||
|
QV('id_dialogclose', (b & 2) || (b & 8));
|
||||||
|
QV('idx_dlgButtonBar', b & 7);
|
||||||
|
if (y) QH('id_dialogtitle', y);
|
||||||
|
for (var i = 1; i < 24; i++) { QV('dialog' + i, i == x); } // Edit this line when more dialogs are added
|
||||||
|
QV('dialog', x);
|
||||||
|
if (c) { if (x == 2) { QH('id_dialogOptions', c); } else { QH('id_dialogMessage', c); } }
|
||||||
|
}
|
||||||
|
|
||||||
|
function dialogclose(x) {
|
||||||
|
var f = xxdialogFunc;
|
||||||
|
var b = xxdialogButtons;
|
||||||
|
var t = xxdialogTag;
|
||||||
|
setDialogMode();
|
||||||
|
if (((b & 8) || x) && f) f(x, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the web page to full screen
|
||||||
|
function toggleFullScreen(toggle) {
|
||||||
|
//if (toggle === 1) { webPageFullScreen = !webPageFullScreen; putstore('webPageFullScreen', webPageFullScreen); }
|
||||||
|
if (webPageFullScreen == false) {
|
||||||
|
// By adding body class, it will change a style of all ellements using CSS selector
|
||||||
|
// No need for JS anymore and it will be consistent style for all the templates.
|
||||||
|
QC('body').remove('fullscreen');
|
||||||
|
} else {
|
||||||
|
QC('body').add('fullscreen');
|
||||||
|
}
|
||||||
|
QV('body', true);
|
||||||
|
center();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle user interface menu
|
||||||
|
function showUserInterfaceSelectMenu() {
|
||||||
|
Q('uiViewButton1').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton2').classList.remove('uiSelectorSel');
|
||||||
|
Q('uiViewButton3').classList.remove('uiSelectorSel');
|
||||||
|
try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
|
||||||
|
QV('uiMenu', (QS('uiMenu').display == 'none'));
|
||||||
|
if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function userInterfaceSelectMenu(s) {
|
||||||
|
if (s) { uiMode = s; putstore('uiMode', uiMode); }
|
||||||
|
webPageFullScreen = (uiMode < 3);
|
||||||
|
//webPageStackMenu = (uiMode > 1);
|
||||||
|
toggleFullScreen(0);
|
||||||
|
//toggleStackMenu(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleNightMode() {
|
||||||
|
nightMode = !nightMode;
|
||||||
|
if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); }
|
||||||
|
putstore('_nightMode', (nightMode ? '1' : '0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function center() {
|
||||||
|
/* Now we use CSS media to achive the same effect as deleted JS */
|
||||||
|
if (webPageFullScreen == false) {
|
||||||
|
QS('centralTable')['margin-top'] = '';
|
||||||
|
} else {
|
||||||
|
var h = ((Q('column_l').clientHeight) / 2) - 220;
|
||||||
|
if (h < 0) h = 0;
|
||||||
|
QS('centralTable')['margin-top'] = h + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
|
||||||
|
function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
|
||||||
|
function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }
|
||||||
|
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
|
function haltReturn(e) { if (e.keyCode == 13) { haltEvent(e); } }
|
||||||
|
function validateEmail(v) { var emailReg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; return emailReg.test(v); } // New version
|
||||||
|
function putstore(name, val) { try { if (typeof (localStorage) === 'undefined') return; localStorage.setItem(name, val); } catch (e) { } }
|
||||||
|
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
|
||||||
|
function format(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function (match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); };
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body></html>
|
1
views/translations/message-min_cs.handlebars
Normal file
1
views/translations/message-min_cs.handlebars
Normal file
@ -0,0 +1 @@
|
|||||||
|
<!doctypehtml><html dir=ltr xmlns=http://www.w3.org/1999/xhtml><meta http-equiv=X-UA-Compatible content="IE=edge"><meta content="text/html;charset=utf-8"http-equiv=Content-Type><meta name=viewport content="user-scalable=1,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name=apple-mobile-web-app-capable content=yes><meta name=format-detection content="telephone=no"><link type=text/css href=/styles/style.css media=screen rel=stylesheet title=CSS><title>MeshCentral - {{{title3}}}</title><div id=container style=max-height:100vh><div id=mastheadx></div><div id=masthead style="background:url(logo.png) 0 0;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden"><div style=float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px><strong><font style=font-size:46px;font-family:Arial,Helvetica,sans-serif>{{{title}}}</font></strong></div><div style=float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px><strong><font style=font-size:14px;font-family:Arial,Helvetica,sans-serif>{{{title2}}}</font></strong></div></div><div id=page_content style=max-height:calc(100vh-138px)><div id=column_l><h1>{{{title3}}}</h1><p style=margin-left:20px>{{{message}}}</p><br></div><div id=footer><table cellpadding=0 cellspacing=10 style=width:100%><tr><td style=text-align:left><td style=text-align:right><a href=terms>Terms & Privacy</a></table></div></div></div>
|
40
views/translations/message_cs.handlebars
Normal file
40
views/translations/message_cs.handlebars
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html><html dir="ltr" xmlns="http://www.w3.org/1999/xhtml"><head>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="viewport" content="user-scalable=1.0,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link type="text/css" href="/styles/style.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<title>MeshCentral - {{{title3}}}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container" style="max-height:100vh">
|
||||||
|
<div id="mastheadx"></div>
|
||||||
|
<div id="masthead" style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden">
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:20px;padding-top:8px">
|
||||||
|
<strong><font style="font-size:46px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:14px">
|
||||||
|
<strong><font style="font-size:14px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="page_content" style="max-height:calc(100vh-138px)">
|
||||||
|
<div id="column_l">
|
||||||
|
<h1>{{{title3}}}</h1>
|
||||||
|
<p style="margin-left:20px">{{{message}}}</p>
|
||||||
|
<br>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<table cellpadding="0" cellspacing="10" style="width:100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td style="text-align:left"></td>
|
||||||
|
<td style="text-align:right">
|
||||||
|
<a href="terms">Terms & Privacy</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body></html>
|
1
views/translations/messenger-min_cs.handlebars
Normal file
1
views/translations/messenger-min_cs.handlebars
Normal file
File diff suppressed because one or more lines are too long
642
views/translations/messenger_cs.handlebars
Normal file
642
views/translations/messenger_cs.handlebars
Normal file
@ -0,0 +1,642 @@
|
|||||||
|
<!DOCTYPE html><html style="height:100%"><head>
|
||||||
|
<title>MeshMessenger</title>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<link type="text/css" href="styles/messenger.css" media="screen" rel="stylesheet" title="CSS">
|
||||||
|
<script type="text/javascript" src="scripts/common-0.0.1.js"></script>
|
||||||
|
<script type="text/javascript" src="scripts/filesaver.js"></script>
|
||||||
|
</head>
|
||||||
|
<body style="font-family:Arial,Helvetica,sans-serif">
|
||||||
|
<div id="xtop" style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray">
|
||||||
|
<div style="position:absolute;background-color:#036;right:0;height:38px">
|
||||||
|
<div id="notifyButton" class="icon13 topButton" style="margin-right:4px;display:none" title="Zapnout notifikace v prohlížeči" onclick="enableNotificationsButtonClick()"></div>
|
||||||
|
<div id="fileButton" class="icon4 topButton" title="Share a file" style="display:none" onclick="fileButtonClick()"></div>
|
||||||
|
<div id="camButton" class="icon2 topButton" title="Activate camera & microphone" style="display:none" onclick="camButtonClick()"></div>
|
||||||
|
<div id="micButton" class="icon6 topButton" title="Activate microphone" style="display:none" onclick="micButtonClick()"></div>
|
||||||
|
<div id="hangupButton" class="icon11 topRedButton" title="Hang up" style="display:none" onclick="hangUpButtonClick(1)"></div>
|
||||||
|
</div>
|
||||||
|
<div style="padding-top:9px;padding-left:6px;font-size:20px;display:inline-block"><b><span id="xtitle">MeshMessenger</span></b></div>
|
||||||
|
</div>
|
||||||
|
<div id="xmiddle" style="position:absolute;left:0;right:0;top:38px;bottom:30px">
|
||||||
|
<div style="position:absolute;left:0;right:0;top:0;bottom:0;overflow-y:scroll">
|
||||||
|
<div id="xmsg" style="position:absolute;left:0;right:0;bottom:0;padding:5px"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="xbottom" style="position:absolute;left:0;right:0;bottom:0px;height:30px;background-color:#036">
|
||||||
|
<div style="position:absolute;left:5px;right:215px;bottom:4px;top:4px;background-color:aliceblue"><input id="xouttext" type="text" style="width:calc(100% - 5px)" onfocus="onUserInputFocus(1)" onblur="onUserInputFocus(0)"></div>
|
||||||
|
<input type="button" id="sendButton" value="Odeslat" style="position:absolute;right:110px;width:100px;top:4px;" onclick="xsend(event)">
|
||||||
|
<input type="button" id="clearButton" value="Clear" style="position:absolute;right:5px;width:100px;top:4px;" onclick="displayClear()">
|
||||||
|
</div>
|
||||||
|
<div id="remoteVideo" style="position:absolute;right:24px;top:45px;width:320px;height:calc(240px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none">
|
||||||
|
<div style="position:absolute;right:0;left:0;top:2.5px;text-align:center">Vzdálený</div>
|
||||||
|
<video id="remoteVideoCanvas" autoplay="" style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:black"></video>
|
||||||
|
</div>
|
||||||
|
<div id="localVideo" style="position:absolute;right:24px;top:320px;width:160px;height:calc(120px + 30px);background-color:gray;border-radius:12px 12px 12px 12px;box-shadow:3px 3px 10px gray;display:none">
|
||||||
|
<div style="position:absolute;right:0;left:0;top:2.5px;text-align:center">Lokální</div>
|
||||||
|
<video id="localVideoCanvas" autoplay="" muted="" style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:black"></video>
|
||||||
|
</div>
|
||||||
|
<input id="uploadFileInput" type="file" multiple="" style="display:none">
|
||||||
|
<script type="text/javascript" onunload="onUnLoad()">
|
||||||
|
var userInputFocus = 0;
|
||||||
|
var args = parseUriArgs();
|
||||||
|
var socket = null; // Websocket object
|
||||||
|
var state = 0; // Connection state. 0 = Disconnected, 1 = Connecting, 2 = Connected.
|
||||||
|
|
||||||
|
// WebRTC sessions and data, audio and video channels
|
||||||
|
var random = Math.random(); // Selected random, larger value initiates WebRTC.
|
||||||
|
var webrtcSessions = { }; // WebRTC objects: 0 for data, 1 for outbound audio/video, 2 for inbound audio/video
|
||||||
|
var webchannel = null; // WebRTC data channel
|
||||||
|
var localStream = null;
|
||||||
|
var remoteStream = null;
|
||||||
|
var multiWebRtc = true; // if set to true, multiple WebRTC sessions will be setup. If false, everything uses one session.
|
||||||
|
var userMediaSupport = 0;
|
||||||
|
var notification = null;
|
||||||
|
getUserMediaSupport(function (x) { userMediaSupport = x; })
|
||||||
|
var webrtcconfiguration = '{{{webrtconfig}}}';
|
||||||
|
if (webrtcconfiguration == '') { webrtcconfiguration = null; } else { try { webrtcconfiguration = JSON.parse(decodeURIComponent(webrtcconfiguration)); } catch (ex) { console.log('Invalid WebRTC config: \"' + webrtcconfiguration + '\".'); webrtcconfiguration = null; } }
|
||||||
|
|
||||||
|
// File transfer state
|
||||||
|
var fileUploads = [];
|
||||||
|
var fileDownloads = {};
|
||||||
|
var currentFileUpload = null;
|
||||||
|
var currentFileDownload = null;
|
||||||
|
|
||||||
|
// Set the title
|
||||||
|
if (args.title) { QH('xtitle', args.title.split(' ').join(' ')); document.title = document.title + ' - ' + args.title; }
|
||||||
|
|
||||||
|
// Setup web notifications
|
||||||
|
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||||
|
|
||||||
|
// Listen to drag & drop events
|
||||||
|
document.addEventListener('dragover', haltEvent, false);
|
||||||
|
document.addEventListener('dragleave', haltEvent, false);
|
||||||
|
document.addEventListener('drop', fileDrop, false);
|
||||||
|
|
||||||
|
document.onclick = function (e) {
|
||||||
|
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||||
|
if (notification != null) { notification.close(); notification = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trap document key up events
|
||||||
|
document.onkeyup = function ondockeypress(e) {
|
||||||
|
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||||
|
if (notification != null) { notification.close(); notification = null; }
|
||||||
|
if (state == 2) {
|
||||||
|
if ((e.keyCode == 8) && (userInputFocus == 0)) {
|
||||||
|
// Backspace
|
||||||
|
var outtext = Q('xouttext').value;
|
||||||
|
if (outtext.length > 0) { Q('xouttext').value = outtext.substring(0, outtext.length - 1); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userInputFocus == 0) { haltEvent(e); return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trap document key presses
|
||||||
|
document.onkeypress = function ondockeypress(e) {
|
||||||
|
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||||
|
if (notification != null) { notification.close(); notification = null; }
|
||||||
|
if (state == 2) {
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
// Return
|
||||||
|
xsend(e);
|
||||||
|
} else {
|
||||||
|
// Any other key
|
||||||
|
if ((userInputFocus == 0) && (e.key.length == 1)) { Q('xouttext').value = Q('xouttext').value + e.key; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userInputFocus == 0) { haltEvent(e); return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUserInputFocus(x) { userInputFocus = x; }
|
||||||
|
function displayClear() { QH('xmsg', ''); cancelAllFileTransfers(); fileUploads = [], fileDownloads = {}; }
|
||||||
|
|
||||||
|
// Polyfill FileReader if needed
|
||||||
|
if (!FileReader.prototype.readAsBinaryString) {
|
||||||
|
FileReader.prototype.readAsBinaryString = function (fileData) {
|
||||||
|
var binary = '', self = this, reader = new FileReader();
|
||||||
|
reader.onload = function (e) {
|
||||||
|
var bytes = new Uint8Array(reader.result);
|
||||||
|
for (var i = 0; i < bytes.byteLength; i++) { binary += String.fromCharCode(bytes[i]); }
|
||||||
|
self.onload({ target: { result: binary } });
|
||||||
|
}
|
||||||
|
reader.readAsArrayBuffer(fileData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect if microphone & camera are present
|
||||||
|
// 0 = nomedia, 1 = miconly, 2 = mic&cam
|
||||||
|
function getUserMediaSupport(func) {
|
||||||
|
try {
|
||||||
|
navigator.mediaDevices.enumerateDevices().then(function (devices) {
|
||||||
|
try {
|
||||||
|
var mic = 0, cam = 0;
|
||||||
|
devices.forEach(function (device) {
|
||||||
|
if (device.kind === 'audioinput') { mic = 1; }
|
||||||
|
if (device.kind === 'videoinput') { cam = 1; }
|
||||||
|
});
|
||||||
|
if (mic == 0) { func(0); }
|
||||||
|
func(mic + cam);
|
||||||
|
} catch (ex) { }
|
||||||
|
})
|
||||||
|
} catch (ex) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display a control message
|
||||||
|
function displayControl(msg) {
|
||||||
|
QA('xmsg', '<div style="clear:both"><div style="color:gray;float:left;margin-bottom:2px">' + msg + '</div><div></div></div>');
|
||||||
|
Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayLocalVideo(active) { QV('localVideo', active); adjustVideoWindows(); }
|
||||||
|
function displayRemoteVideo(active) { QV('remoteVideo', active); adjustVideoWindows(); }
|
||||||
|
function adjustVideoWindows() {
|
||||||
|
//var lv = (QS('localVideo')['display'] != 'none');
|
||||||
|
var rv = (QS('remoteVideo')['display'] != 'none');
|
||||||
|
QS('localVideo')['top'] = rv ? '320px' : '45px';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display a message from the remote user
|
||||||
|
function displayRemote(msg) {
|
||||||
|
QA('xmsg', '<div style="clear:both"><div class="remoteBubble">' + msg + '</div><div></div></div>');
|
||||||
|
Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
|
||||||
|
|
||||||
|
// If web notifications are granted, use it.
|
||||||
|
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||||
|
if (Notification && (Notification.permission == 'granted')) {
|
||||||
|
if (notification != null) { notification.close(); notification = null; }
|
||||||
|
if (args.title) {
|
||||||
|
notification = new Notification("MeshMessenger" + ' - ' + args.title, { body: msg });
|
||||||
|
} else {
|
||||||
|
notification = new Notification("MeshMessenger", { body: msg });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display and send a message from the local user
|
||||||
|
function xsend(event) {
|
||||||
|
if (notification != null) { notification.close(); notification = null; }
|
||||||
|
if (Notification) { QV('notifyButton', Notification.permission != 'granted'); }
|
||||||
|
var outtext = Q('xouttext').value;
|
||||||
|
if (outtext.length > 0) {
|
||||||
|
Q('xouttext').value = '';
|
||||||
|
QA('xmsg', '<div style="clear:both"><div class="localBubble">' + outtext + '</div><div></div></div>');
|
||||||
|
Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
|
||||||
|
send({ action: 'chat', msg: outtext });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
|
||||||
|
function parseUriArgs() { var name, r = {}, parsedUri = window.document.location.href.split(/[\?&|\=]/); parsedUri.splice(0, 1); for (x in parsedUri) { switch (x % 2) { case 0: { name = decodeURIComponent(parsedUri[x]); break; } case 1: { r[name] = decodeURIComponent(parsedUri[x]); var x = parseInt(r[name]); if (x == r[name]) { r[name] = x; } break; } default: { break; } } } return r; }
|
||||||
|
|
||||||
|
// Update user controls
|
||||||
|
function updateControls() {
|
||||||
|
QE('sendButton', state == 2);
|
||||||
|
QE('clearButton', state == 2);
|
||||||
|
QE('xouttext', state == 2);
|
||||||
|
QV('fileButton', state == 2);
|
||||||
|
QV('camButton', webchannel && webchannel.ok && !localStream && (userMediaSupport == 2));
|
||||||
|
QV('micButton', webchannel && webchannel.ok && !localStream && (userMediaSupport > 0));
|
||||||
|
QV('hangupButton', webchannel && webchannel.ok && localStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the WebRTC setup
|
||||||
|
function startWebRTC(id, startDataChannel) {
|
||||||
|
if ((webrtcSessions[0] != null) && (multiWebRtc == false)) { return webrtcSessions[0]; };
|
||||||
|
|
||||||
|
// Setup the WebRTC object
|
||||||
|
var webrtc = null;
|
||||||
|
if (typeof RTCPeerConnection !== 'undefined') { webrtc = new RTCPeerConnection(webrtcconfiguration); }
|
||||||
|
else if (typeof webkitRTCPeerConnection !== 'undefined') { webrtc = new webkitRTCPeerConnection(webrtcconfiguration); }
|
||||||
|
if (webrtc == null) return null; // No WebRTC support.
|
||||||
|
|
||||||
|
webrtc.id = id;
|
||||||
|
webrtc.onicecandidate = function (e) { try { if (e.candidate != null) { sendws({ action: 'webRtcIce', ice: e.candidate, id: this.id }); } } catch (ex) { } }
|
||||||
|
webrtc.oniceconnectionstatechange = function () { if (webrtc && webrtc.iceConnectionState == 'failed') { webrtc.close(); if (webrtcSessions[webrtc.id]) { delete webrtcSessions[webrtc.id]; } } }
|
||||||
|
webrtc.ondatachannel = function (ev) {
|
||||||
|
//console.log('ondatachannel');
|
||||||
|
webchannel = ev.channel;
|
||||||
|
webchannel.onmessage = function (event) { processMessage(event.data, 2); };
|
||||||
|
webchannel.onopen = function () { webchannel.ok = true; updateControls(); sendws({ action: 'rtcSwitch', v: 0 }); };
|
||||||
|
webchannel.onclose = function (event) { if (webchannel && webchannel.ok) { disconnect(); } else { hangUpButtonClick(0); } }
|
||||||
|
}
|
||||||
|
webrtc.onnegotiationneeded = function (event) {
|
||||||
|
if (webrtc.holdTimer != null) return;
|
||||||
|
webrtc.holdTimer = setTimeout(function () { // This time is needed to keep Chrome from being to excited. Wait until we add all tracks before kicking this off.
|
||||||
|
//console.log('onnegotiationneeded', id);
|
||||||
|
webrtc.holdTimer = null;
|
||||||
|
webrtc.createOffer(function (offer) { /*console.log('offer', offer.sdp.length);*/ webrtc.setLocalDescription(offer, function () { sendws({ action: 'webRtcSdp', sdp: offer, id: id }); }, function () { hangUpButtonClick(id); }); }, function () { hangUpButtonClick(id); });
|
||||||
|
}, 20);
|
||||||
|
}
|
||||||
|
webrtc.ontrack = function (event) {
|
||||||
|
//console.log('ontrack', id);
|
||||||
|
var video = Q('remoteVideoCanvas');
|
||||||
|
video.srcObject = remoteStream = event.streams[0];
|
||||||
|
video.onloadedmetadata = function (e) { video.play(); };
|
||||||
|
displayRemoteVideo(true);
|
||||||
|
}
|
||||||
|
//webrtc.onremovetrack = function (event) { console.log('onremovetrack'); }
|
||||||
|
//webrtc.onicegatheringstatechange = function (event) { console.log('onicegatheringstatechange', event); }
|
||||||
|
//webrtc.onsignalingstatechange = function (event) { console.log('onsignalingstatechange', event); }
|
||||||
|
|
||||||
|
// Initiate the WebRTC offer or handle the offer from the peer.
|
||||||
|
if (startDataChannel == true) {
|
||||||
|
webchannel = webrtc.createDataChannel('DataChannel', {}); // { ordered: false, maxRetransmits: 2 }
|
||||||
|
webchannel.onmessage = function (event) { processMessage(event.data, 2); };
|
||||||
|
webchannel.onopen = function () { webchannel.ok = true; updateControls(); sendws({ action: 'rtcSwitch', v: 0 }); };
|
||||||
|
webchannel.onclose = function (event) { if (webchannel && webchannel.ok) { disconnect(); } else { hangUpButtonClick(0); } }
|
||||||
|
}
|
||||||
|
|
||||||
|
webrtcSessions[id] = webrtc;
|
||||||
|
return webrtc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function webRtcHandleOffer(id, description) {
|
||||||
|
//console.log('webRtcHandleOffer', description.sdp.length);
|
||||||
|
var webrtc = webrtcSessions[id];
|
||||||
|
if (webrtc) {
|
||||||
|
webrtc.setRemoteDescription(new RTCSessionDescription(description), function () {
|
||||||
|
if (description.type == 'offer') {
|
||||||
|
webrtc.createAnswer(function (answer) {
|
||||||
|
webrtc.setLocalDescription(answer, function (a, b) {
|
||||||
|
try { sendws({ action: 'webRtcSdp', sdp: answer, id: id }); } catch (ex) { }
|
||||||
|
}, function () { hangUpButtonClick(id); });
|
||||||
|
}, function () { hangUpButtonClick(id); });
|
||||||
|
}
|
||||||
|
}, function () { hangUpButtonClick(id); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicate to peer that data traffic will no longer be sent over websocket and start holding traffic.
|
||||||
|
function performWebRtcSwitch() {
|
||||||
|
if (webchannel && webchannel.ok) { sendws({ action: 'rtcSwitch', v: 1 }); webchannel.xoutBuffer = []; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect everything
|
||||||
|
function disconnect() {
|
||||||
|
if (state > 0) { displayControl("Connection closed."); }
|
||||||
|
if (state > 1) { setTimeout(start, 500); }
|
||||||
|
cancelAllFileTransfers();
|
||||||
|
hangUpButtonClick(0, true); // Data channel
|
||||||
|
hangUpButtonClick(1, true); // Local audio/video
|
||||||
|
hangUpButtonClick(2, true); // Remote audio/video
|
||||||
|
if (socket != null) { socket.close(); socket = null; }
|
||||||
|
updateControls();
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data over the current transport (WebRTC first)
|
||||||
|
function send(data) {
|
||||||
|
if (state != 2) return; // If not in connected state, ignore this.
|
||||||
|
if (typeof data == 'object') { data = JSON.stringify(data); } // If this is an object, convert it to a string.
|
||||||
|
if (webchannel && webchannel.ok) { if (webchannel.xoutBuffer != null) { webchannel.xoutBuffer.push(data); } else { webchannel.send(data); } } // If WebRTC channel is possible, use it or hold until we can use it.
|
||||||
|
else { if (socket != null) { try { socket.send(data); } catch (ex) { } } } // If a websocket channel is present, use that.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data over the websocket transport (WebSocket only)
|
||||||
|
function sendws(data) {
|
||||||
|
if (state != 2) return;
|
||||||
|
//console.log('SEND', data);
|
||||||
|
if (typeof data == 'object') { data = JSON.stringify(data); }
|
||||||
|
if (socket != null) { socket.send(data); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebRTC id switcher (0 -> 0, 1 -> 2, 2 -> 1)
|
||||||
|
function webRtcIdSwitch(id) { if (id == 0) { return 0; } return 3 - id; }
|
||||||
|
|
||||||
|
// Process incoming messages
|
||||||
|
function processMessage(data, transport) {
|
||||||
|
if (typeof data == 'string') {
|
||||||
|
try { data = JSON.parse(data); } catch (ex) { console.log('Unable to parse', data); return; }
|
||||||
|
//console.log('RECV', data);
|
||||||
|
switch (data.action) {
|
||||||
|
case 'chat': { displayRemote(data.msg); break; } // Incoming chat message.
|
||||||
|
case 'random': { if (random > data.random) { startWebRTC(0, true); } break; } // If we have a larger random value, we start WebRTC.
|
||||||
|
case 'webRtcSdp': { if (!webrtcSessions[webRtcIdSwitch(data.id)]) { startWebRTC(webRtcIdSwitch(data.id), false); } webRtcHandleOffer(webRtcIdSwitch(data.id), data.sdp); break; } // Remote WebRTC offer or answer.
|
||||||
|
case 'webRtcIce': { var webrtc = webrtcSessions[webRtcIdSwitch(data.id)]; if (webrtc) { try { webrtc.addIceCandidate(new RTCIceCandidate(data.ice)); } catch (ex) { } } break; } // Remote ICE candidate
|
||||||
|
case 'videoStop': { hangUpButtonClick(webRtcIdSwitch(data.id), true); break; }
|
||||||
|
case 'rtcSwitch': { // WebRTC switch over commands.
|
||||||
|
switch (data.v) {
|
||||||
|
case 0: { performWebRtcSwitch(); break; } // Other side is ready for switch over to WebRTC
|
||||||
|
case 1: { sendws({ action: 'rtcSwitch', v: 2 }); break; } // Other side no longer sending data on websocket, confirm we got the end marker
|
||||||
|
case 2: { for (var i in webchannel.xoutBuffer) { webchannel.send(webchannel.xoutBuffer[i]); } delete webchannel.xoutBuffer; break; } // Send any pending data over WebRTC and start using WebRTC with all traffic
|
||||||
|
default: { console.log('Unknown rtcSwitch value: ' + data.action); break; } //
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'file': { startFileDownload(data); break; }
|
||||||
|
case 'fileUploadCancel': { cancelFileTransfer(data.id); break; }
|
||||||
|
case 'fileUploadStart': {
|
||||||
|
if (fileDownloads[data.id]) {
|
||||||
|
currentFileDownload = fileDownloads[data.id];
|
||||||
|
currentFileDownload.data = '';
|
||||||
|
changeFileInfo(data.id, 2, 0);
|
||||||
|
continueFileDownload(data);
|
||||||
|
send({ action: 'fileUploadAck', id: data.id });
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
case 'fileUploadEnd': {
|
||||||
|
if (currentFileDownload && (currentFileDownload.id == data.id)) {
|
||||||
|
changeFileInfo(data.id, 3, 200);
|
||||||
|
currentFileDownload.done = 1;
|
||||||
|
currentFileDownload = null;
|
||||||
|
send({ action: 'fileUploadAck', id: data.id });
|
||||||
|
}
|
||||||
|
currentFileDownload = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'fileUploadAck': {
|
||||||
|
continueFileUpload();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'fileData': {
|
||||||
|
if (currentFileDownload && (currentFileDownload.id == data.id)) {
|
||||||
|
currentFileDownload.data += data.data;
|
||||||
|
changeFileInfo(data.id, 2, (currentFileDownload.data.length * 200 / currentFileDownload.size));
|
||||||
|
send({ action: 'fileUploadAck', id: data.id });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: { console.log('Unhandled object data', data); break; }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Unhandled data', typeof data, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// File sharing button
|
||||||
|
function fileButtonClick() {
|
||||||
|
var chooser = Q('uploadFileInput');
|
||||||
|
if (chooser.getAttribute('eventset') != 1) {
|
||||||
|
chooser.setAttribute('eventset', '1');
|
||||||
|
chooser.addEventListener('change', fileSelect, false);
|
||||||
|
}
|
||||||
|
chooser.value = null;
|
||||||
|
chooser.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
// User selected one or more files to upload to remote user.
|
||||||
|
function fileSelect() {
|
||||||
|
if (state != 2) return;
|
||||||
|
var x = Q('uploadFileInput');
|
||||||
|
if (x.files.length > 10) {
|
||||||
|
displayControl("Max. 10 souběžně nahrávaných souborů.");
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < x.files.length; i++) {
|
||||||
|
if (x.files[i].size > 0) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
|
||||||
|
reader.xfile = x.files[i];
|
||||||
|
reader.readAsBinaryString(x.files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// User drag & droped one or more files to upload to remote user.
|
||||||
|
function fileDrop(e) {
|
||||||
|
haltEvent(e);
|
||||||
|
if ((state != 2) || (e.dataTransfer == null)) return;
|
||||||
|
if (e.dataTransfer.files.length > 10) {
|
||||||
|
displayControl("Max. 10 souběžně nahrávaných souborů.");
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < e.dataTransfer.files.length; i++) {
|
||||||
|
if (e.dataTransfer.files[i].size > 0) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
|
||||||
|
reader.xfile = e.dataTransfer.files[i];
|
||||||
|
reader.readAsBinaryString(e.dataTransfer.files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startFileUpload(file) {
|
||||||
|
if (state != 2) return;
|
||||||
|
file.id = Math.random();
|
||||||
|
fileUploads.push(file);
|
||||||
|
QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\'' + file.id + '\')"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden;white-space:nowrap;" title="' + file.name + '">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px"> </div></div></div></div>');
|
||||||
|
Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
|
||||||
|
send({ action: 'file', size: file.size, id: file.id, type: file.type, name: file.name });
|
||||||
|
if (currentFileUpload == null) continueFileUpload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startFileDownload(file) {
|
||||||
|
if (state != 2) return;
|
||||||
|
fileDownloads[file.id] = file;
|
||||||
|
QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="remoteBubble" style="width:240px;cursor:pointer" onclick="saveFileTransfer(\'' + file.id + '\')"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden;white-space:nowrap;" title="' + file.name + '">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px"> </div></div></div></div>');
|
||||||
|
Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the file icon and progress
|
||||||
|
function changeFileInfo(id, icon, progress, progressColor) {
|
||||||
|
if (icon) {
|
||||||
|
Q('FILEUP-ICON-' + id).classList.remove('fileicon');
|
||||||
|
Q('FILEUP-ICON-' + id).classList.remove('fileiconx');
|
||||||
|
Q('FILEUP-ICON-' + id).classList.remove('fileicontransfer');
|
||||||
|
Q('FILEUP-ICON-' + id).classList.remove('fileicondone');
|
||||||
|
Q('FILEUP-ICON-' + id).classList.add(['fileicon', 'fileiconx', 'fileicontransfer', 'fileicondone'][icon]);
|
||||||
|
}
|
||||||
|
if (progress) { QS('FILEUP-PROGRESS-' + id)['width'] = progress + 'px'; }
|
||||||
|
if (progressColor) { QS('FILEUP-PROGRESS-' + id)['background-color'] = progressColor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a string into a blob
|
||||||
|
function data2blob(data) {
|
||||||
|
var bytes = new Array(data.length);
|
||||||
|
for (var i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i);
|
||||||
|
return new Blob([new Uint8Array(bytes)]);
|
||||||
|
};
|
||||||
|
|
||||||
|
function saveFileTransfer(id) {
|
||||||
|
var f = fileDownloads[id];
|
||||||
|
if (f && f.done == 1) { saveAs(data2blob(f.data), f.name); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelFileTransfer(id) {
|
||||||
|
if ((currentFileUpload != null) && (currentFileUpload.id == id)) { currentFileUpload = null; }
|
||||||
|
if ((currentFileDownload != null) && (currentFileDownload.id == id)) { currentFileDownload = null; }
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
if (fileDownloads[id] && (fileDownloads[id].done != 1)) {
|
||||||
|
delete fileDownloads[id];
|
||||||
|
found = true;
|
||||||
|
} else {
|
||||||
|
for (var i in fileUploads) {
|
||||||
|
if (fileUploads[i].id == id) {
|
||||||
|
send({ action: 'fileUploadCancel', id: id });
|
||||||
|
fileUploads.splice(i, 1);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) { changeFileInfo(id, 1, 200, 'gray'); } // Only cancel a file if it was in the file queue.
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelAllFileTransfers() {
|
||||||
|
for (var i in fileDownloads) { cancelFileTransfer(fileDownloads[i].id); }
|
||||||
|
for (var i in fileUploads) { cancelFileTransfer(fileUploads[i].id); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function continueFileUpload() {
|
||||||
|
if (currentFileUpload == null) {
|
||||||
|
// Select the next file to upload
|
||||||
|
if (fileUploads.length == 0) { return; } // Nothing to do
|
||||||
|
currentFileUpload = fileUploads[0];
|
||||||
|
currentFileUpload.ptr = 0;
|
||||||
|
|
||||||
|
// Indicate that we are sending this file
|
||||||
|
send({ action: 'fileUploadStart', size: currentFileUpload.size, id: currentFileUpload.id, type: currentFileUpload.type, name: currentFileUpload.name });
|
||||||
|
} else {
|
||||||
|
if (currentFileUpload.size <= currentFileUpload.ptr) {
|
||||||
|
// If we are done, send the end marker
|
||||||
|
send({ action: 'fileUploadEnd', size: currentFileUpload.size, id: currentFileUpload.id, type: currentFileUpload.type, name: currentFileUpload.name });
|
||||||
|
changeFileInfo(currentFileUpload.id, 3, 200);
|
||||||
|
fileUploads.splice(0, 1);
|
||||||
|
currentFileUpload = null;
|
||||||
|
continueFileUpload(); // Send the next file
|
||||||
|
} else {
|
||||||
|
// Send the next block
|
||||||
|
var nextBlockLen = Math.min(4000, currentFileUpload.data.length - currentFileUpload.ptr);
|
||||||
|
var data = currentFileUpload.data.substring(currentFileUpload.ptr, currentFileUpload.ptr + nextBlockLen);
|
||||||
|
send({ action: 'fileData', id: currentFileUpload.id, data: data });
|
||||||
|
currentFileUpload.ptr += nextBlockLen;
|
||||||
|
changeFileInfo(currentFileUpload.id, 0, (currentFileUpload.ptr * 200 / currentFileUpload.size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function continueFileDownload(msg) {
|
||||||
|
send({ action: 'fileUploadAck', id: msg.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle notification
|
||||||
|
function enableNotificationsButtonClick() {
|
||||||
|
if (Notification) { Notification.requestPermission().then(function (permission) { QV('notifyButton', permission != 'granted'); }); }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Camera button
|
||||||
|
function camButtonClick() {
|
||||||
|
if (localStream == null) { startLocalStream({ video: true, audio: true }); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Microphone
|
||||||
|
function micButtonClick() {
|
||||||
|
if (localStream == null) { startLocalStream({ video: false, audio: true }); }
|
||||||
|
}
|
||||||
|
|
||||||
|
function hangUpButtonClick(id, fromRemote) {
|
||||||
|
//console.log('hangUpButtonClick', id);
|
||||||
|
var localVideo = Q('localVideoCanvas');
|
||||||
|
var remoteVideo = Q('remoteVideoCanvas');
|
||||||
|
var webrtc = webrtcSessions[(multiWebRtc == true)? id : 0];
|
||||||
|
|
||||||
|
if ((id == 0) && (webchannel != null)) { try { webchannel.close(); } catch (e) { } webchannel = null; }
|
||||||
|
|
||||||
|
if (webrtc) {
|
||||||
|
if ((multiWebRtc == true) || (id == 0)) {
|
||||||
|
webrtc.ontrack = null;
|
||||||
|
webrtc.onremovetrack = null;
|
||||||
|
webrtc.onremovestream = null;
|
||||||
|
webrtc.onnicecandidate = null;
|
||||||
|
webrtc.oniceconnectionstatechange = null;
|
||||||
|
webrtc.onsignalingstatechange = null;
|
||||||
|
webrtc.onicegatheringstatechange = null;
|
||||||
|
webrtc.onnotificationneeded = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((id == 1) && localStream) { var tracks = localStream.getTracks(); for (var i in tracks) { tracks[i].stop(); } localStream = null; }
|
||||||
|
if ((id == 2) && remoteStream) { var tracks = remoteStream.getTracks(); for (var i in tracks) { tracks[i].stop(); } remoteStream = null; }
|
||||||
|
|
||||||
|
if ((multiWebRtc == true) || (id == 0)) {
|
||||||
|
webrtc.close();
|
||||||
|
delete webrtcSessions[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == 1) {
|
||||||
|
localVideo.removeAttribute('src');
|
||||||
|
localVideo.removeAttribute('srcObject');
|
||||||
|
if (localStream != null) { localStream = null; }
|
||||||
|
displayLocalVideo(false);
|
||||||
|
} else if (id == 2) {
|
||||||
|
remoteVideo.removeAttribute('src');
|
||||||
|
remoteVideo.removeAttribute('srcObject');
|
||||||
|
displayRemoteVideo(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromRemote != true) { send({ action: 'videoStop', id: id }); }
|
||||||
|
updateControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup local audio/video
|
||||||
|
function startLocalStream(constraints) {
|
||||||
|
var channel = (multiWebRtc == true) ? 1 : 0;
|
||||||
|
if (localStream != null) return;
|
||||||
|
if ((multiWebRtc == true) && (webrtcSessions[1] != null)) return;
|
||||||
|
if (navigator.mediaDevices.getUserMedia) {
|
||||||
|
localStream = 1;
|
||||||
|
updateControls();
|
||||||
|
navigator.mediaDevices.getUserMedia(constraints)
|
||||||
|
.then(function (stream) {
|
||||||
|
localStream = stream;
|
||||||
|
var tracks = localStream.getTracks();
|
||||||
|
var webrtc = startWebRTC(channel);
|
||||||
|
if (constraints.video == true) {
|
||||||
|
var video = Q('localVideoCanvas');
|
||||||
|
video.srcObject = stream;
|
||||||
|
video.onloadedmetadata = function (e) { video.play(); };
|
||||||
|
displayLocalVideo(true);
|
||||||
|
}
|
||||||
|
for (var i in tracks) { webrtc.addTrack(tracks[i], localStream); }
|
||||||
|
}, function (err) {
|
||||||
|
displayControl(err.message + '.');
|
||||||
|
hangUpButtonClick(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the main start
|
||||||
|
function start() {
|
||||||
|
// Get started
|
||||||
|
updateControls();
|
||||||
|
if ((typeof args.id == 'string') && (args.id.length > 0)) {
|
||||||
|
var url = window.location.protocol.replace('http', 'ws') + '//' + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + '/meshrelay.ashx?id=' + args.id;
|
||||||
|
if ((args.auth != null) && (args.auth != '')) { url += '&auth=' + args.auth; }
|
||||||
|
socket = new WebSocket(url);
|
||||||
|
socket.onopen = function () { state = 1; displayControl("Čekání na ostatní uživatele..."); }
|
||||||
|
socket.onerror = function (e) { /*console.error(e);*/ }
|
||||||
|
socket.onclose = function () { disconnect(); }
|
||||||
|
socket.onmessage = function (msg) {
|
||||||
|
if ((state < 2) && (typeof msg.data == 'string') && ((msg.data == 'c') || (msg.data == 'cr'))) {
|
||||||
|
hangUpButtonClick(0, true);
|
||||||
|
hangUpButtonClick(1, true);
|
||||||
|
hangUpButtonClick(2, true);
|
||||||
|
displayControl("Připojeno.");
|
||||||
|
state = 2;
|
||||||
|
updateControls();
|
||||||
|
sendws({ action: 'random', random: random }); // Send a random number. Higher number starts the WebRTC session.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state == 2) { processMessage(msg.data, 1); }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
displayControl("Error: No connection key specified.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start();
|
||||||
|
|
||||||
|
function onUnLoad() {
|
||||||
|
for (var i = 0; i < 3; i++) { if (webrtcSessions[i]) { webrtcSessions[i].close(); delete webrtcSessions[i]; } }
|
||||||
|
if (webchannel != null) { try { webchannel.close(); } catch (e) { } webchannel = null; }
|
||||||
|
if (socket != null) { try { socket.close(); } catch (e) { } socket = null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body></html>
|
Loading…
Reference in New Issue
Block a user