Ylianst / MeshCentral

A complete web-based remote monitoring and management web site. Once setup you can install agents and perform remote desktop session to devices on the local network or over the Internet.
https://meshcentral.com
Apache License 2.0
4.26k stars 570 forks source link

customized handlebars files can not be translated #6022

Closed cfoellmann closed 5 months ago

cfoellmann commented 7 months ago

modifying views for a domain in meshcentral-web or meshcentral-web-domain2 do only work for language = en

The translation tool seems to not pick up these modified files and does not translate.

si458 commented 7 months ago

ok ive added a fix to my PR so you can use node node_modules/meshcentral.js --translate HOWEVER i cant fix the translate in the WEB UI yet as ths requires some work because the webui just calls the translate.js file, but the translate.js file has no knowlege of the domains etc (which is correct as its a standalone utility)

si458 commented 7 months ago

ok ive merged the PR, which means you create your files default.handlebars, login2.handlebars, etc in your views folder, then you can run node node_modules/meshcentral --translate and let it translate/minify all your files! you can also use https://MYMESHSERVER.COM/translator.htm, edit translations, then save to server and run the --translate command (DONT USE THE TRANSLATE SERVER BUTTON IN THE WEB UI!) im still looking into the button as it only translates the default views folder inside meshcentral and not your web folders you create

cfoellmann commented 5 months ago

@si458 I have changed a lot of stuff in the default.handlebars file. Now it stopped working to modify it.

I connect of the console of the docker container and run "meshcentral.js --translate" which generates translation in the mapped folder meshcentral/web-csystems/views/translations as default_de.handlebars in the folder in views. These generated files reflect the changed template but it is not loaded in the UI (if set to non-EN)

How can that be? Is the location not respected anymore?

si458 commented 5 months ago

@cfoellmann do you have minify:true set? has the --translate produced -min.handlebars files?

cfoellmann commented 5 months ago

yes, it has produced those and those contain the "new" code

si458 commented 5 months ago

have you tried ctrl+f5 and also restarting the meshcentral container? also try setting minify: false then restarting the container and seeing if your changes get applied.

cfoellmann commented 5 months ago

I had a look at my config.json and it is already minify: false set. For both domains like in the definition shown. But it is still producing -min files.

Everything refreshed. ctrl+F5, browser cache, container restart, restartserver command. is there more?

si458 commented 5 months ago

oh hang on ive just re-read ur message.

so you changed default.handlebars in /opt/meshcentral/web-csystems/views then ran translate which generates the files correctly and if you load up ENGLISH it loads ur custom file correctly BUT if you load up say german/french/etc, its loading the original translate files and not your custom file thats been translated!

will have alook into it!

cfoellmann commented 5 months ago

not really.

it used to work. but now it wont pick up new changes. I am on the latest :master the translate function is killing me.

cfoellmann commented 5 months ago

One more thing:

I used the following command from within the container node /opt/meshcentral/meshcentral/meshcentral.js --translate

I will use the way described in #6168

cfoellmann commented 5 months ago

And I have not refreshed the template from the master.

That is a very bad merge since my git does not show my commit changes. probably because of the file size (Line count)

DaanSelen commented 5 months ago

The --translate operation exits with an error (presumably) after these lines:

...
Translating HTML (hu): device-notify.html
Translating HTML (hu): device-help.html
Translating TXT (hu): account-check.txt
Translating TXT (hu): account-invite.txt
Translating TXT (hu): account-login.txt
Translating TXT (hu): account-reset.txt
Translating TXT (hu): mesh-invite.txt
Translating TXT (hu): device-notify.txt
Translating TXT (hu): device-help.txt
Translating TXT (hu): sms-messages.txt
Translating JSON (All): agent-translations.json
Translating JSON (All): coretranslations.json
Processing HTML: agentinvite.handlebars
Processing HTML: invite.handlebars
Processing HTML: default.handlebars
Processing HTML: default-mobile.handlebars
Processing HTML: download.handlebars
Processing HTML: download2.handlebars
Processing HTML: error404.handlebars
Processing HTML: error404-mobile.handlebars
Processing HTML: login.handlebars
Processing HTML: login2.handlebars
Processing HTML: login-mobile.handlebars
Processing HTML: terms.handlebars
Processing HTML: terms-mobile.handlebars
Processing HTML: xterm.handlebars
Processing HTML: message.handlebars
Processing HTML: message2.handlebars
Processing HTML: messenger.handlebars
Processing HTML: player.handlebars
Processing HTML: sharing.handlebars
Processing HTML: mstsc.handlebars
Processing HTML: ssh.handlebars
Processing HTML: account-check.html
Processing HTML: account-invite.html
Processing HTML: account-login.html
Processing HTML: account-reset.html
Processing HTML: mesh-invite.html
Processing HTML: device-notify.html
Processing HTML: device-help.html
Processing TXT: account-check.txt
Processing TXT: account-invite.txt
Processing TXT: account-login.txt
Processing TXT: account-reset.txt
Processing TXT: mesh-invite.txt
Processing TXT: device-notify.txt
Processing TXT: device-help.txt
Processing TXT: sms-messages.txt
Processing JSON: agent-translations.json
Processing JSON: coretranslations.json
3379 strings in output file.
Generating default-min.handlebars...

I can only see the bottom half (I hope its half) of the error which comes down to this:

...
;
                var vers_not_compat = ' [ <span onclick="return setDialogMode(2, \'Compatibility Issue\', 1, null, \'This plugin version is not compatible with your MeshCentral installation, please upgrade MeshCentral first.\');" title="' + "Version incompatible, please upgrade your MeshCentral installation first" + '" style="cursor: pointer; color:red;"> ! </span> ]';

                var tbl = Q('p42tbl');
                installedPluginList.forEach(function(p){
                    var cant_action = [];
                    if (p.hasAdminPanel == true && p.status) {
                        p.nameHtml = '<a onclick="return goPlugin(\'' + p.shortName + '\', \'' + p.name.replace(/'/g, "\\'") + '\');">' + EscapeHtml(p.name) + '</a>';
                    } else {
                        p.nameHtml = EscapeHtml(p.name);
                    }
                    p.statusText = statusMap[p.status].text;
                    p.statusColor = statusMap[p.status].color;

                    if (p.versionHistoryUrl == null) { cant_action.push('downgrade'); }
                    if (!p.status) { p.version = ' - '; } // It isn't technically installed, so no version number
                    p.upgradeAvail = "Checking...";
                    if (installedPluginList['version_info'] != null && installedPluginList['version_info'][p._id] != null) {
                        var vin = installedPluginList['version_info'][p._id];
                        if (vin.hasUpdate) {
                            p.upgradeAvail = '<a title="' + "View Changelog" + '" rel="noreferrer noopener" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
                        } else {
                            cant_action.push('upgrade');
                            if (p.status) p.upgradeAvail = "Up to date";
                            else p.upgradeAvail = '<a title="' + "View Changelog" + '" rel="noreferrer noopener" target="_blank" href="' + vin.changelogUrl + '">' + vin.version + '</a>';
                        }
                        if (!vin.meshCentralCompat) {
                            p.upgradeAvail += vers_not_compat;
                            cant_action.push('install');
                            cant_action.push('upgrade');
                        }
                    }

                    p.actions = '<select onchange="return pluginAction(this,\'' + p._id + '\');"><option value=""> --</option>';
                    var entries = Object.entries(statusAvailability[p.status]);
                    for (var k in entries) {
                        if (cant_action.indexOf(entries[k][0]) === -1) {
                            p.actions += '<option value="' + entries[k][0] + '">' + entries[k][1] + '</option>';
                        }
                    }
                    p.actions += '</select>';

                    var tpl = '<td><img style=margin-top:3px src=images/plugin24.png></td><td class=gradTable1>&nbsp;</td><td class=gradTable2>' + p.nameHtml + '</td><td class=gradTable2>' + EscapeHtml(p.description) + '</td><td class=gradTable2 style=text-align:center><a href="' + EscapeHtml(p.homepage) + '" rel="noreferrer noopener" target="_blank">Home</a></td><td class=gradTable2 style=text-align:center>' + EscapeHtml(p.version) + '</td><td style=text-align:center class="pluginUpgradeAvailable gradTable2">' + p.upgradeAvail + '</td><td class=gradTable2 style="text-align:center;color:#' + p.statusColor + '">' + p.statusText + '</td><td class="pluginAction gradTable2" style=text-align:center>' + p.actions + '</td><td class=gradTable3>&nbsp;</td>';
                    var tr = tbl.insertRow(-1);
                    tr.innerHTML = tpl;
                    tr.classList.add('p42tblRow');
                    tr.setAttribute('data-id', p._id);
                    tr.setAttribute('id', 'pluginRow-' + p._id);
                });
            } else {
                var tr = Q('p42tbl').querySelectorAll('.p42tblRow');
                for (var i in Object.values(tr)) { tr[i].parentNode.removeChild(tr[i]); }
            }
            if (versInfo == null) refreshPluginLatest();
        }

        function refreshPluginLatest() {
            if (pluginHandler == null) return;
            meshserver.send({ action: 'pluginLatestCheck' });
        }

        function distributeCore() {
            if (pluginHandler == null) return;
            meshserver.send({ action: 'distributeCore', nodes: nodes }); // All nodes the user has access to
            QV('pluginRestartNotice', false);
        }

        function pluginActionEx() {
            if (pluginHandler == null) return;
            var act = Q('lastPluginAct').value, id = Q('lastPluginId').value, pVersUrl = Q('lastPluginVersion').value;

            switch(act) {
                case 'upgrade':
                case 'install':
                    meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': false });
                    break;
                case 'downgrade':
                    Q('lastPluginVersion').querySelectorAll('option').forEach(function(opt) {
                        if (opt.value == pVersUrl) pVers = opt.text;
                    });
                    meshserver.send({ 'action': 'installplugin', 'id': id, 'version_only': { 'name': pVers, 'url': pVersUrl }});
                    break;
                case 'delete':
                    meshserver.send({ 'action': 'removeplugin', 'id': id });
                    break;
                case 'disable':
                    meshserver.send({ 'action': 'disableplugin', 'id': id });
                    break;
            }
            QV('pluginRestartNotice', true);
        }

        function pluginAction(elem, id) {
            if (pluginHandler == null) return;
            if (elem.value == 'downgrade') {
                meshserver.send({ 'action': 'getpluginversions', 'id': id });
            } else {
                var plugin = null;
                for (var i in installedPluginList) { if (installedPluginList[i]._id == id) { plugin = installedPluginList[i]; } }
                setDialogMode(2, "Plugin Action", 3, pluginActionEx, format("Are you sure you want to {0} the plugin: {1}", elem.value, plugin.name) + '<input id="lastPluginAct" type="hidden" value="' + elem.value + '" /><input id="lastPluginId" type="hidden" value="' + id + '" /><input id="lastPluginVersion" type="hidden" value="" />');
            }
            elem.value = '';
        }

        function goPlugin(pname, title) {
            if (pluginHandler == null) return;
            if (pname == null) { Q('p43iframe').src = ''; } else { QH('p43title', title); Q('p43iframe').src = '/pluginadmin.ashx?pin=' + pname; go(43); }
        }

        //
        // Access Control Functions
        // These must match server
        //

        // Remove user rights
        function removeUserRights(rights, userid) {
            if ((userid != userinfo._id) || (userinfo.removeRights == null)) return rights;
            var add = 0, substract = 0;
            if ((userinfo.removeRights & 0x00000008) != 0) { substract += 0x00000008; } // No Remote Control
            if ((userinfo.removeRights & 0x00010000) != 0) { add += 0x00010000; } // No Desktop
            if ((userinfo.removeRights & 0x00000100) != 0) { add += 0x00000100; } // Desktop View Only
            if ((userinfo.removeRights & 0x00000200) != 0) { add += 0x00000200; } // No Terminal
            if ((userinfo.removeRights & 0x00000400) != 0) { add += 0x00000400; } // No Files
            if ((userinfo.removeRights & 0x00000010) != 0) { substract += 0x00000010; } // No Console
            if ((userinfo.removeRights & 0x00008000) != 0) { substract += 0x00008000; } // No Uninstall
            if ((userinfo.removeRights & 0x00020000) != 0) { substract += 0x00020000; } // No Remote Command
            if ((userinfo.removeRights & 0x00000040) != 0) { substract += 0x00000040; } // No Wake
            if ((userinfo.removeRights & 0x00040000) != 0) { substract += 0x00040000; } // No Reset/Off
            if (rights != 0xFFFFFFFF) {
                // If not administrator, add and subsctract restrictions
                rights |= add;
                rights &= (0xFFFFFFFF - substract);
            } else {
                // If administrator for a device group, start with permissions and add and subsctract restrictions
                rights = 1 + 2 + 4 + 8 + 32 + 64 + 128 + 16384 + 32768 + 131072 + 262144 + 524288 + 1048576;
                rights |= add;
                rights &= (0xFFFFFFFF - substract);
            }
            return rights;
        }

        // Get the right of a user on a given device group
        function GetMeshRights(mesh, userid) {
            if (mesh == null) { return 0; }
            if (userid == null) { userid = userinfo._id; }
            if (typeof mesh == 'string') { mesh = meshes[mesh] }
            if ((mesh == null) || (mesh.links == null)) { return 0; }

            // Check if super user
            if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return removeUserRights(0xFFFFFFFF, userid);

            // Check device group link permission
            var rights = 0, r = mesh.links[userid];
            if (r != null) {
                if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a device group link, stop here.
                rights = r.rights;
            }

            // Check permissions thru user groups
            var user = null;
            if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
            if (user != null) {
                for (var i in user.links) {
                    if (i.startsWith('ugrp/')) {
                        r = mesh.links[i];
                        if (r != null) {
                            if (r.rights == 0xFFFFFFFF) { return removeUserRights(0xFFFFFFFF, userid); } // User has full rights thru a user group, stop here.
                            rights |= r.rights; // TODO: Deal with reverse permissions
                        }
                    }
                }
            }

            return removeUserRights(rights, userid);
        }

        // Returns true if the user can view the given device group
        function IsMeshViewable(mesh, userid) {
            if (mesh == null) { return false; }
            if (userid == null) { userid = userinfo._id; }
            if (typeof mesh == 'string') { mesh = meshes[mesh] }
            if ((mesh == null) || (mesh.links == null)) { return false; }
            if (mesh.links[userid] != null) { return true; } // User has visilibity thru a direct link

            // Check if user user
            if (serverinfo.manageAllDeviceGroups && (userid == userinfo._id)) return true;

            // Check permissions thru user groups
            var user = null;
            if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
            if (user != null) {
                for (var i in user.links) {
                    if ((i.startsWith('ugrp/')) && (mesh.links[i] != null)) { return true; } // User has visilibity thru a user group
                }
            }

            return false;
        }

        // Return the user rights for a given node
        function GetNodeRights(node, userid) {
            if (node == null) { return 0; }
            if (userid == null) { userid = userinfo._id; }
            if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return 0; } }
            var r = GetMeshRights(node.meshid, userid);
            if (r == 0xFFFFFFFF) return removeUserRights(r, userid);

            // Check direct device rights using device data
            if ((node.links != null) && (node.links[userid] != null)) { r |= node.links[userid].rights; } // TODO: Deal with reverse permissions

            // Check direct device rights thru user groups
            if ((node.links != null) && (userinfo.links != null)) {
                for (var i in node.links) {
                    if (i.startsWith('ugrp/') && (userinfo.links[i] != null) && (node.links[i].rights != null)) { r |= node.links[i].rights; }
                }
            }

            // Check direct device rights using user data
            /*
            var user = null;
            if (userid == userinfo._id) { user = userinfo; } else { if (users != null) { user = users[userid]; } }
            if ((user != null) && (user.links != null)) {
                var r2 = user.links[node._id];
                if (r2 != null) {
                    if (r2.rights == 0xFFFFFFFF) { return 0xFFFFFFFF; } // User has full rights thru a device link, stop here.
                    r |= r2.rights; // TODO: Deal with reverse permissions
                }
            }
            */
            return removeUserRights(r, userid);
        }

        // Return true if the device is visible to the user
        function IsNodeViewable(node, userid) {
            if (node == null) { return false; }
            if (userid == null) { userid = userinfo._id; }
            if (typeof node == 'string') { node = getNodeFromId(node); if (node == null) { return false; } }
            if (IsMeshViewable(node.meshid, userid)) return true;

            // Check direct device visibility using device data
            if ((node.links != null) && (node.links[userid] != null)) { return true; }

            // Check direct device visibility thru user groups
            if ((node.links != null) && (userinfo.links != null)) {
                for (var i in node.links) { if (i.startsWith('ugrp/') && (userinfo.links[i] != null) && (node.links[i].rights != null)) { return true; } }
            }

            return false;
        }

        //
        // Generic methods
        //

        // Converts string to UTF8 byte array, polyfill for IE.
        // Following method is code from Mozilla: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
        if (typeof TextEncoder === 'undefined') {
            window.TextEncoder=function TextEncoder(){};
            TextEncoder.prototype.encode = function encode(str) {
                'use strict';
                var Len = str.length, resPos = -1;
                var resArr = typeof Uint8Array === 'undefined' ? new Array(Len * 1.5) : new Uint8Array(Len * 3);
                for (var point=0, nextcode=0, i = 0; i !== Len; ) {
                    point = str.charCodeAt(i), i += 1;
                    if (point >= 0xD800 && point <= 0xDBFF) {
                        if (i === Len) { resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; resArr[resPos += 1] = 0xbd; break; }
                        nextcode = str.charCodeAt(i);
                        if (nextcode >= 0xDC00 && nextcode <= 0xDFFF) {
                            point = (point - 0xD800) * 0x400 + nextcode - 0xDC00 + 0x10000;
                            i += 1;
                            if (point > 0xffff) { resArr[resPos += 1] = (0x1e<<3) | (point>>>18); resArr[resPos += 1] = (0x2<<6) | ((point>>>12)&0x3f); resArr[resPos += 1] = (0x2<<6) | ((point>>>6)&0x3f); resArr[resPos += 1] = (0x2<<6) | (point&0x3f); continue; }
                        } else { resArr[resPos += 1] = 0xef; resArr[resPos += 1] = 0xbf; resArr[resPos += 1] = 0xbd; continue; }
                    }
                    if (point <= 0x007f) {
                        resArr[resPos += 1] = (0x0<<7) | point;
                    } else if (point <= 0x07ff) {
                        resArr[resPos += 1] = (0x6<<5) | (point>>>6); resArr[resPos += 1] = (0x2<<6) | (point&0x3f);
                    } else {
                        resArr[resPos += 1] = (0xe<<4) | (point>>>12); resArr[resPos += 1] = (0x2<<6) | ((point>>>6)&0x3f); resArr[resPos += 1] = (0x2<<6) | (point&0x3f);
                    }
                }
                if (typeof Uint8Array !== 'undefined') return resArr.subarray(0, resPos + 1);
                resArr.length = resPos + 1;
                return resArr;
            };
            TextEncoder.prototype.toString = function(){return '[object TextEncoder]'};
            try {
                Object.defineProperty(TextEncoder.prototype,'encoding',{
                    get:function(){ if(TextEncoder.prototype.isPrototypeOf(this)) return'utf-8'; else throw TypeError('Illegal invocation'); }
                });
            } catch(e) { TextEncoder.prototype.encoding = 'utf-8'; }
            if (typeof Symbol!=='undefined')TextEncoder.prototype[Symbol.toStringTag]='TextEncoder';
        }

        // Used to convert Base64 public VAPID key to bytearray.
        function urlBase64ToUint8Array(base64String) {
            var padding = '='.repeat((4 - base64String.length % 4) % 4);
            var base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
            var rawData = atob(base64);
            var outputArray = new Uint8Array(rawData.length);
            for (var i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); }
            return outputArray;
        }

        function joinPaths() { var x = []; for (var i in arguments) { var w = arguments[i]; if ((w != null) && (w != '')) { while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); } while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); } x.push(w); } } return x.join('/'); }
        function putstore(name, val) {
            try {
                if ((typeof (localStorage) === 'undefined') || (localStorage.getItem(name) == val)) return;
                if (val == null) { localStorage.removeItem(name); } else { localStorage.setItem(name, val); }
            } catch (ex) { }
            if (name[0] != '_') {
                var s = {};
                try {
                    for (var i = 0, len = localStorage.length; i < len; ++i) {
                        var k = localStorage.key(i);
                        if (k[0] != '_') {
                            s[k] = localStorage.getItem(k);
                            if ((k != 'desktopsettings') && (k != 'stars') && (k != 'deskKeyShortcuts') && (k != 'deskStrings') && (k != 'cmdopt') && (typeof s[k] == 'string') && (s[k].length > 64)) { delete s[k]; }
                        }
                    }
                } catch (ex) {}
                meshserver.send({ action: 'userWebState', state: JSON.stringify(s) });
            }
        }

        // Convert a string into a UTF8 blob with the UTF8 header in front of it.
        function stringToUtf8Blob(str) {
            const bytes = new TextEncoder().encode(str);
            var bytes2 = new Uint8Array(3 + bytes.length);
            bytes2[0] = 0xEF; // This is the UTF-8 header for CSV files, add it to the start of the file.
            bytes2[1] = 0xBB;
            bytes2[2] = 0xBF;
            for (var i = 0; i < bytes.length; i++) { bytes2[i + 3] = bytes[i]; }
            return new Blob([bytes2], { type: 'application/octet-stream' }) // application/json;charset=utf-8
        }

        // Convert a string into a UTF8 blob
        function stringToUtf8BlobNoHeader(str) {
            return new Blob([new TextEncoder().encode(str)], { type: 'application/octet-stream' }) // application/json;charset=utf-8
        }

        function multiTranslate(s) { var i = s.indexOf(']|'); return s.substring(i + 2); } // Used when an English string can have different meanings, so "[MEANING]|word" is used instead as translation key.
        function getLang() { if (navigator.languages != undefined) { return navigator.languages[0]; } return navigator.language; }
        function getNodeAmtVersion(node) { if ((node == null) || (node.intelamt == null) || (typeof node.intelamt.ver != 'string')) return 0; var verSplit = node.intelamt.ver.split('.'); if (verSplit.length < 2) return 0; return parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); }
        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 addLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <img class=hoverButton src=images/link5.png></span>'; }
        function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
        function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
        function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
        function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
        function methodcheck(r) { if (r && r != null && r.Body && r.Body.ReturnValueStr != 'SUCCESS') { messagebox("Call Error", r.Header.Method + ': ' + r.Body.ReturnValueStr.replace('_', ' ')); return true; } return false; }
        function TableStart() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=200px><p><td>'; }
        function TableStart2() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td>'; }
        function TableEntry(n, v) { return '<tr><td><p>' + n + '<td>' + v; }
        function FullTable(x, e) { var r = TableStart(); for (i in x) { if (i && x[i]) r += TableEntry(i, x[i]); } return r + TableEnd(e); }
        function TableEnd(n) { return '<tr><td colspan=2><p>' + (n?n:'') + '</table>'; }
        function AddButton(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '" style=margin:4px>'; }
        function AddButton2(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '">'; }
        function AddRefreshButton(f) { return '<input type=button name=refreshbtn value=Refresh onclick="refreshButtons(false);' + f + '" style=margin:4px ' + (refreshButtonsState==false?'disabled':'') + '>'; }
        function MoreStart() { return '<div id=idx_dlgMoreButtons3 style=display:none><hr>'; };
        function MoreEnd() { return '</div>'; };
        function MoreToggle(v) { QV('idx_dlgMoreButtons1',!v); QV('idx_dlgMoreButtons2',v); QV('idx_dlgMoreButtons3',v); }
        function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
        function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
        function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
        function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + '-' + g.substring(10, 12) + g.substring(8, 10) + '-' + g.substring(14, 16) + g.substring(12, 14) + '-' + g.substring(16, 20) + '-' + g.substring(20); }
        function getUrlVars() { var j, hash, vars = [], hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { j = hashes[i].indexOf('='); if (j > 0) { vars[hashes[i].substring(0, j)] = hashes[i].substring(j + 1, hashes[i].length); } } return vars; }
        //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 addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px><b>' + v + '</b></div><div>' + t + '</div></div>'; }
        function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
        function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
        function addHtmlValue3(t, v) { return '<div><b>' + t + '</b></div><div style=margin-left:16px>' + v + '</div>'; }
        function addHtmlValue4(t, v) { return '<table style=width:100%><td style=width:120px>' + t + '<td style=text-align:right><b>' + v + '</b></table>'; }
        function addHtmlValue5(t, v) { return '<div style=padding:4px><div style=display:inline-block;float:right><b>' + v + '</b></div><div style=display:inline-block>' + t + '</div></div>'; }
        function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
        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 isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
        function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
        function findOne(arr1, arr2) { if ((arr1 == null) || (arr2 == null)) return false; return arr2.some(function (v) { return arr1.indexOf(v) >= 0; }); };
        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(); }
        function copyTextToClip2(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 = decodeURIComponent(txt); document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
        function capitalizeFirstLetter(x) { return x.charAt(0).toUpperCase() + x.slice(1); }
        function printDate(d) { return d.toLocaleDateString(args.locale); }
        function printTime(d) { return d.toLocaleTimeString(args.locale); }
        function printDateTime(d) { return d.toLocaleString(args.locale); }
        function printFlexDateTime(d) { if (printDate(new Date()) == printDate(d)) { return printTime(d); } else { return printDateTime(d); } }
        function addDetailItem(title, value, state) { return '<table style=width:100%><td>' + nobreak(title) + '<td style=text-align:right>' + value + '</table>'; }
        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; }); };
        function addTextLink(subtext, text, link) { var i = text.toLowerCase().indexOf(subtext.toLowerCase()); if (i == -1) { return text; } return text.substring(0, i) + '<a href="' + link + '">' + subtext + '</a>' + text.substring(i + subtext.length); }
        function getOrderedList(objList, oname) { var r = []; for (var i in objList) { r.push(objList[i]); } r.sort(function(a, b) { var aa = a[oname].toLowerCase(), bb = b[oname].toLowerCase(); if (aa > bb) return 1; if (aa < bb) return -1; return 0; }); return r; }
        function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); }
        function nobreak(x) { return x.split(' ').join('&nbsp;'); }
        function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
        function encodeURIComponentEx(txt) { return encodeURIComponent(txt).replace(/'/g,'%27'); };
        function getUserName(userid) {
            var useridsplit = userid.split('/'), userid2 = useridsplit[0] + '/' + useridsplit[1] + '/' + useridsplit[2], guestname = '';
            if ((useridsplit.length == 4) && (useridsplit[3].startsWith('guest:'))) { guestname = ' - ' + decode_utf8(atob(useridsplit[3].substring(6))); }
            if (users && users[userid2] != null) { if (users[userid2].realname != null) return (users[userid2].realname + guestname); else return (users[userid2].name + guestname); }
            return (useridsplit[2] + guestname);
        }
        function round(value, precision) { var multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; }
        function safeNewWindow(url, target) { var newWindow = window.open(url, target, 'noopener,noreferrer'); if (newWindow) { newWindow.opener = null; } }
        function isWindowsNode(node) { if ((node.mtype != 2) || (node.agent == null) || (node.agent.id == null)) return false; return ([1,2,3,4,21,22,34].indexOf(node.agent.id) >= 0); }

        // Webkit seems to have a problem with "download" tag causing "network error", but openning the download in a hidden frame fixes it.
        // So we do that for all browsers except FireFox
        function downloadFile(link, name, closeDialog) {
            var element = document.createElement('a');
            element.setAttribute('href', link);
            element.setAttribute('rel', 'noreferrer noopener');
            element.setAttribute('target', 'fileDownloadFrame');
            if (navigator.userAgent.indexOf('Firefox') >= 0) { element.setAttribute('download', decodeURIComponent(name?name:'')); }
            document.body.appendChild(element);
            element.click();
            document.body.removeChild(element);
            if (closeDialog) { setDialogMode(0); }
        }

        // Make the dialog box movable
        function dialogBoxDrag() {
            var elmnt = Q('dialog');
            var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
            Q('dialogHeader').onmousedown = dragMouseDown;
            function dragMouseDown(e) {
                e = e || window.event;
                e.preventDefault();
                pos3 = e.clientX;
                pos4 = e.clientY;
                document.onmouseup = closeDragElement;
                document.onmousemove = elementDrag;
            }
            function elementDrag(e) {
                e = e || window.event;
                e.preventDefault();
                pos1 = pos3 - e.clientX;
                pos2 = pos4 - e.clientY;
                pos3 = e.clientX;
                pos4 = e.clientY;
                elmnt.style.top = (elmnt.offsetTop - pos2) + 'px';
                elmnt.style.left = (elmnt.offsetLeft - pos1) + 'px';
            }
            function closeDragElement() {
                document.onmouseup = null;
                document.onmousemove = null;
            }
        }

        // Request Confirmation if closing while a desktop, terminal session is active
        window.addEventListener('beforeunload', function (e) {
            if (((desktop != null) && (xxcurrentView == 11)) || ((terminal != null) && (xxcurrentView == 12))) { e.preventDefault(); e.returnValue = ''; }
        });

    </script>
</body>
</html>
    at new HTMLParser (/opt/meshcentral/node_modules/meshcentral/node_modules/html-minifier/src/htmlparser.js:244:13)
    at minify (/opt/meshcentral/node_modules/meshcentral/node_modules/html-minifier/src/htmlminifier.js:980:3)
    at exports.minify (/opt/meshcentral/node_modules/meshcentral/node_modules/html-minifier/src/htmlminifier.js:1341:16)
    at Object.startEx (/opt/meshcentral/node_modules/meshcentral/translate/translate.js:508:31)
    at CreateMeshCentralServer.obj.Start (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:240:41)
    at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4147:24
    at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
    at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4144:9
    at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
    at mainStart (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3978:5)

Node.js v18.19.0
si458 commented 5 months ago

HUH? 😕

will try have a look tonight/2moz, as i havent changed anything for the translate since https://github.com/Ylianst/MeshCentral/pull/6027

cfoellmann commented 5 months ago

I did refresh the default.handlebars and did another node /opt/meshcentral/meshcentral/meshcentral.js --translate resulting in correct files in web-csystems/views/translations. Ignoring minify: false which is no problem. But the views are being use from some other location with another old version of my translated template. just fyi

cfoellmann commented 5 months ago

I finally found the files that are being used: Although it is translating correctly it is again falling for the views/ files from the default domain '' :-(

DaanSelen commented 5 months ago

I finally found the files that are being used: Although it is translating correctly it is again falling for the views/ files from the default domain '' :-(

So you have not found a cause yet?

cfoellmann commented 5 months ago

no, it is doing minification despite the minify: false and it is ignoring the views from the second domain folder.

DaanSelen commented 5 months ago

I am using a custom meshcentral-web folder, so I do not know if that's relevant

si458 commented 5 months ago

hello all, sorry for delay, been poorly again (wish my body would tell colds to do one and not return!)

my findings on things

  1. node node_modules/meshcentral --translate now translates/minify all files correctly views folders inside node_modules/meshcentral meshcentral-web and meshcentral-web-subdomain its slow translating because its using 1 core instead of 8 cores but it works!
  2. using meshcentral-web works for ENGLISH AND OTHER LANGUAGES verified this by changing the title line in default.handlebars to says titlehere-mainweb in meshcentral-web then translate it and restarting meshcentral
  3. using meshcentral-web-subdomain for ENGLISH works! again i verified this by changing the title line in default.handlebars to says titlehere-subdomainweb in meshcentral-web then translate it and restarting meshcentral
  4. using meshcentral-web-subdomain for NON-ENGLISH doesnt work! it seems to be just using the meshcentral-web versions of NON-ENGLISH!
si458 commented 5 months ago

ok ive found the issue! going to take awhile to fix but im on it! on startup it builds a list of files and languages, from either the default location OR the meshcentral-web folder! its just totally ignoring the fact we can now customise by each domain too!

fileOptions {
  bs: '/home/simon/meshcentral/meshcentral-web/views/translations/default_bs',
  cs: '/home/simon/meshcentral/meshcentral-web/views/translations/default_cs',
  da: '/home/simon/meshcentral/meshcentral-web/views/translations/default_da',
  de: '/home/simon/meshcentral/meshcentral-web/views/translations/default_de',
  es: '/home/simon/meshcentral/meshcentral-web/views/translations/default_es',
  fi: '/home/simon/meshcentral/meshcentral-web/views/translations/default_fi',
  fr: '/home/simon/meshcentral/meshcentral-web/views/translations/default_fr',
  hi: '/home/simon/meshcentral/meshcentral-web/views/translations/default_hi',
  hu: '/home/simon/meshcentral/meshcentral-web/views/translations/default_hu',
  it: '/home/simon/meshcentral/meshcentral-web/views/translations/default_it',
  ja: '/home/simon/meshcentral/meshcentral-web/views/translations/default_ja',
  ko: '/home/simon/meshcentral/meshcentral-web/views/translations/default_ko',
  nl: '/home/simon/meshcentral/meshcentral-web/views/translations/default_nl',
  pl: '/home/simon/meshcentral/meshcentral-web/views/translations/default_pl',
  'pt-br': '/home/simon/meshcentral/meshcentral-web/views/translations/default_pt-br',
  pt: '/home/simon/meshcentral/meshcentral-web/views/translations/default_pt',
  ru: '/home/simon/meshcentral/meshcentral-web/views/translations/default_ru',
  sv: '/home/simon/meshcentral/meshcentral-web/views/translations/default_sv',
  tr: '/home/simon/meshcentral/meshcentral-web/views/translations/default_tr',
  'zh-chs': '/home/simon/meshcentral/meshcentral-web/views/translations/default_zh-chs',
  'zh-cht': '/home/simon/meshcentral/meshcentral-web/views/translations/default_zh-cht'
}
si458 commented 5 months ago

all fixed! #6180 if you want to look/apply the fix!

si458 commented 5 months ago

basically its as explained above, it builds an array of files and languages from 'views' and 'meshcentral-web' and totally forgetting about 'meshcentral-web-domain'! so now it builds the array, and falls back so use meshcentral-web-domain if a file exists in the language or english then use meshcentral-web if a file exists in that language or english then use views if a file exists in that language or english then all else 404 as what have you done with the default 'views' folder!?

cfoellmann commented 5 months ago

the current :master is broken for me.

2024-06-17T08:35:22.377051000Z   SHA384 cert hash: xxx
2024-06-17T08:35:22.377257000Z   SHA384 key hash: yyy
2024-06-17T08:35:22.457112000Z ERR: node:internal/modules/cjs/loader:1143
2024-06-17T08:35:22.457406000Z   const err = new Error(message);
2024-06-17T08:35:22.457571000Z               ^
2024-06-17T08:35:22.457833000Z Error: Cannot find module 'connect-flash'
2024-06-17T08:35:22.457979000Z Require stack:
2024-06-17T08:35:22.458115000Z - /opt/meshcentral/meshcentral/webserver.js
2024-06-17T08:35:22.458313000Z - /opt/meshcentral/meshcentral/meshcentral.js
2024-06-17T08:35:22.458463000Z     at Module._resolveFilename (node:internal/modules/cjs/loader:1143:15)
2024-06-17T08:35:22.458602000Z     at Module._load (node:internal/modules/cjs/loader:984:27)
2024-06-17T08:35:22.458740000Z     at Module.require (node:internal/modules/cjs/loader:1231:19)
2024-06-17T08:35:22.458884000Z     at require (node:internal/modules/helpers:179:18)
2024-06-17T08:35:22.459024000Z     at setupDomainAuthStrategy (/opt/meshcentral/meshcentral/webserver.js:7191:21)
2024-06-17T08:35:22.459238000Z     at setupAllDomainAuthStrategies (/opt/meshcentral/meshcentral/webserver.js:6504:88)
2024-06-17T08:35:22.459378000Z     at serverStart (/opt/meshcentral/meshcentral/webserver.js:6491:13)
2024-06-17T08:35:22.459524000Z     at /opt/meshcentral/meshcentral/webserver.js:309:17
2024-06-17T08:35:22.459661000Z     at /opt/meshcentral/meshcentral/db.js:2028:136
2024-06-17T08:35:22.459803000Z     at Query.<anonymous> (/opt/meshcentral/meshcentral/db.js:1301:39) {
2024-06-17T08:35:22.459940000Z   code: 'MODULE_NOT_FOUND',
2024-06-17T08:35:22.460087000Z   requireStack: [
2024-06-17T08:35:22.460274000Z     '/opt/meshcentral/meshcentral/webserver.js',
2024-06-17T08:35:22.460425000Z     '/opt/meshcentral/meshcentral/meshcentral.js'
2024-06-17T08:35:22.460566000Z   ]
2024-06-17T08:35:22.460697000Z }
2024-06-17T08:35:22.460970000Z Node.js v20.12.1
2024-06-17T08:35:22.493619000Z Error: Command failed: /usr/bin/node /opt/meshcentral/meshcentral/meshcentral --configfile config.json --launch 7
2024-06-17T08:35:22.493849000Z node:internal/modules/cjs/loader:1143
2024-06-17T08:35:22.494009000Z   const err = new Error(message);
2024-06-17T08:35:22.494222000Z               ^
2024-06-17T08:35:22.494504000Z Error: Cannot find module 'connect-flash'
2024-06-17T08:35:22.494638000Z Require stack:
2024-06-17T08:35:22.494770000Z - /opt/meshcentral/meshcentral/webserver.js
2024-06-17T08:35:22.494904000Z - /opt/meshcentral/meshcentral/meshcentral.js
2024-06-17T08:35:22.495028000Z     at Module._resolveFilename (node:internal/modules/cjs/loader:1143:15)
2024-06-17T08:35:22.495221000Z     at Module._load (node:internal/modules/cjs/loader:984:27)
2024-06-17T08:35:22.495395000Z     at Module.require (node:internal/modules/cjs/loader:1231:19)
2024-06-17T08:35:22.495532000Z     at require (node:internal/modules/helpers:179:18)
2024-06-17T08:35:22.495658000Z     at setupDomainAuthStrategy (/opt/meshcentral/meshcentral/webserver.js:7191:21)
2024-06-17T08:35:22.495804000Z     at setupAllDomainAuthStrategies (/opt/meshcentral/meshcentral/webserver.js:6504:88)
2024-06-17T08:35:22.495936000Z     at serverStart (/opt/meshcentral/meshcentral/webserver.js:6491:13)
2024-06-17T08:35:22.496073000Z     at /opt/meshcentral/meshcentral/webserver.js:309:17
2024-06-17T08:35:22.496259000Z     at /opt/meshcentral/meshcentral/db.js:2028:136
2024-06-17T08:35:22.496402000Z     at Query.<anonymous> (/opt/meshcentral/meshcentral/db.js:1301:39) {
2024-06-17T08:35:22.496545000Z   code: 'MODULE_NOT_FOUND',
2024-06-17T08:35:22.496684000Z   requireStack: [
2024-06-17T08:35:22.496815000Z     '/opt/meshcentral/meshcentral/webserver.js',
2024-06-17T08:35:22.496957000Z     '/opt/meshcentral/meshcentral/meshcentral.js'
2024-06-17T08:35:22.497083000Z   ]
2024-06-17T08:35:22.497283000Z }
2024-06-17T08:35:22.497545000Z Node.js v20.12.1
2024-06-17T08:35:22.497804000Z     at genericNodeError (node:internal/errors:984:15)
2024-06-17T08:35:22.497949000Z     at wrappedFn (node:internal/errors:538:14)
2024-06-17T08:35:22.498110000Z     at ChildProcess.exithandler (node:child_process:422:12)
2024-06-17T08:35:22.498310000Z     at ChildProcess.emit (node:events:530:35)
2024-06-17T08:35:22.498438000Z     at maybeClose (node:internal/child_process:1105:16)
2024-06-17T08:35:22.498556000Z     at ChildProcess._handle.onexit (node:internal/child_process:305:5) {
2024-06-17T08:35:22.498731000Z   code: 1,
2024-06-17T08:35:22.498841000Z   killed: false,
2024-06-17T08:35:22.498973000Z   signal: null,
2024-06-17T08:35:22.499142000Z   cmd: '/usr/bin/node /opt/meshcentral/meshcentral/meshcentral --configfile config.json --launch 7'
2024-06-17T08:35:22.499319000Z }
2024-06-17T08:35:22.499469000Z ERROR: MeshCentral failed with critical error, check mesherrors.txt. Restarting in 5 seconds...
si458 commented 5 months ago

@cfoellmann just go into /opt/meshcentral/meshcentral and do an npm list

Check if connect-flash is there

If not do npm install connect-flash and restart container.

I will have another quick look as I did move the connect-flash include but i might of moved it too soon on the start-up

cfoellmann commented 5 months ago

was not in the list.

did a npm install connect-flash. -> works now

si458 commented 5 months ago

yeh its ok ive fixed the bug, doing a few merges of things and new builds! the connect-flash is only used with oidc but was trying to include if you didnt use it! but moved it back to only include with oidc! but i have a feeling its needed for saml too now, so just double checking, thanks for catching the bug tho!

DaanSelen commented 5 months ago

I had to also install jsdom for the --translate option to work which added a lot of vulnerabilities... unfortunately.

root@mesh:/opt/meshcentral# node node_modules/meshcentral --translate
Installing modules [ 'jsdom@22.1.0', 'minify-js@0.0.4', 'html-minifier@4.0.0' ]
Using default translate.json.
node:internal/modules/cjs/loader:1137
  throw err;
  ^

Error: Cannot find module 'jsdom'
Require stack:
- /opt/meshcentral/node_modules/meshcentral/translate/translate.js
- /opt/meshcentral/node_modules/meshcentral/meshcentral.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1134:15)
    at Module._load (node:internal/modules/cjs/loader:975:27)
    at Module.require (node:internal/modules/cjs/loader:1225:19)
    at require (node:internal/modules/helpers:177:18)
    at Object.startEx (/opt/meshcentral/node_modules/meshcentral/translate/translate.js:172:13)
    at CreateMeshCentralServer.obj.Start (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:227:33)
    at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4147:24
    at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:3922:9
    at ChildProcess.exithandler (node:child_process:414:7)
    at ChildProcess.emit (node:events:517:28) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/opt/meshcentral/node_modules/meshcentral/translate/translate.js',
    '/opt/meshcentral/node_modules/meshcentral/meshcentral.js'
  ]
}

Node.js v18.19.0
root@mesh:/opt/meshcentral# npm install jsdom
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated chokidar@1.7.0: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.

added 149 packages, and audited 715 packages in 4s

43 packages are looking for funding
  run `npm fund` for details

63 vulnerabilities (1 low, 4 moderate, 18 high, 40 critical)

To address issues that do not require attention, run:
  npm audit fix

Some issues need review, and may require choosing
a different dependency.

Is this normal?

si458 commented 5 months ago

@cfoellmann ok fixed the connect-flash https://github.com/Ylianst/MeshCentral/commit/7955bc49549be93b8605f9f825e27ab2261bb5f7 as its needed in a few places, not just oidc!

@DaanSelen yes thats perfectly normal, for some mad reason (yet to find out why?) even tho we tell meshcentral to install the translate modules (as they arent needed by default) when it then included them a few seconds after installing them, it cant find them? BUT if you then re-run the command, it finds them no problems! its as if NodeJS is caching what modules are installed when you first run the command, but then not reloading them when you do an npm install while its running, so you have to run it again for it to go oh looks theres a module that wasnt there before, ill load it

P.S both, just pushed new commit so new master images be ready soon for you to try with the language translate fixes in!

cfoellmann commented 5 months ago

where the --translate fixes not in?

I tried a --translate and it still giving me the views from the custom domain folder :-(

si458 commented 5 months ago

@cfoellmann try the new master image from 2 mins ago https://github.com/Ylianst/MeshCentral/pkgs/container/meshcentral https://github.com/users/Ylianst/packages/container/meshcentral/230915165?tag=master

you might have to re-run the --translate function and let it regenerate all the translations, then restart the container for meshcentral to pick it up

DaanSelen commented 5 months ago

@DaanSelen yes thats perfectly normal,

I was talking about the vulnerabilities introduces with this npm installation,

cfoellmann commented 5 months ago

@si458 working now. very much appreciated as always!!

@DaanSelen I am pretty sure that most of the packages installed on the "start" of meshcentral would produce the "same" warnings: The npm feature to show vulnerabilities is a good thing but with these many inter-dependencies (715 packages) it is nearly impossible to get a working result without some outdated packages in there, right? @si458

si458 commented 5 months ago

@DaanSelen sorry having a mad monday morning, mis-read message completely. yes its normal to see the 63 vulnerabilities (1 low, 4 moderate, 18 high, 40 critical) line because npm install warns you so you can update packages if needs be. as @DaanSelen explained, packages require packages, require packages require packages, so tracking down WHICH ONES are vulnerable is time consuming, but we do try to stay on top of package updates and make sure not to break meshcenteal in the process!

p.s: dont forget to donate ❤️ https://www.si458.co.uk/2024/01/05/donation/

DaanSelen commented 5 months ago

For me this issue still persists.

} catch (ex) {}
                meshserver.send({ action: 'userWebState', state: JSON.stringify(s) });
            }
        }

        // Convert a string into a UTF8 blob with the UTF8 header in front of it.
        function stringToUtf8Blob(str) {
            const bytes = new TextEncoder().encode(str);
            var bytes2 = new Uint8Array(3 + bytes.length);
            bytes2[0] = 0xEF; // This is the UTF-8 header for CSV files, add it to the start of the file.
            bytes2[1] = 0xBB;
            bytes2[2] = 0xBF;
            for (var i = 0; i < bytes.length; i++) { bytes2[i + 3] = bytes[i]; }
            return new Blob([bytes2], { type: 'application/octet-stream' }) // application/json;charset=utf-8
        }

        // Convert a string into a UTF8 blob
        function stringToUtf8BlobNoHeader(str) {
            return new Blob([new TextEncoder().encode(str)], { type: 'application/octet-stream' }) // application/json;charset=utf-8
        }

        function multiTranslate(s) { var i = s.indexOf(']|'); return s.substring(i + 2); } // Used when an English string can have different meanings, so "[MEANING]|word" is used instead as translation key.
        function getLang() { if (navigator.languages != undefined) { return navigator.languages[0]; } return navigator.language; }
        function getNodeAmtVersion(node) { if ((node == null) || (node.intelamt == null) || (typeof node.intelamt.ver != 'string')) return 0; var verSplit = node.intelamt.ver.split('.'); if (verSplit.length < 2) return 0; return parseInt(verSplit[0]) + (parseInt(verSplit[1]) / 100); }
        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 addLink(x, f) { return '<span tabindex=0 style=cursor:pointer;text-decoration:none onclick=\'' + f + '\' onkeypress="if (event.key==\'Enter\') {' + f + '} ">' + x + ' <img class=hoverButton src=images/link5.png></span>'; }
        function addLinkConditional(x, f, c) { if (c) return addLink(x, f); return x; }
        function haltEvent(e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
        function addOption(q, t, i) { var option = document.createElement('option'); option.text = t; option.value = i; Q(q).add(option); }
        function passwordcheck(p) { return (p.length > 7) && (/\d/.test(p)) && (/[a-z]/.test(p)) && (/[A-Z]/.test(p)) && (/\W/.test(p)); }
        function methodcheck(r) { if (r && r != null && r.Body && r.Body.ReturnValueStr != 'SUCCESS') { messagebox("Call Error", r.Header.Method + ': ' + r.Body.ReturnValueStr.replace('_', ' ')); return true; } return false; }
        function TableStart() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td width=200px><p><td>'; }
        function TableStart2() { return '<table cellpadding=0 cellspacing=0 style=width:100%;border-radius:8px><tr><td><p><td>'; }
        function TableEntry(n, v) { return '<tr><td><p>' + n + '<td>' + v; }
        function FullTable(x, e) { var r = TableStart(); for (i in x) { if (i && x[i]) r += TableEntry(i, x[i]); } return r + TableEnd(e); }
        function TableEnd(n) { return '<tr><td colspan=2><p>' + (n?n:'') + '</table>'; }
        function AddButton(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '" style=margin:4px>'; }
        function AddButton2(v, f) { return '<input type=button value="' + v + '" onclick="' + f + '">'; }
        function AddRefreshButton(f) { return '<input type=button name=refreshbtn value=Refresh onclick="refreshButtons(false);' + f + '" style=margin:4px ' + (refreshButtonsState==false?'disabled':'') + '>'; }
        function MoreStart() { return '<div id=idx_dlgMoreButtons3 style=display:none><hr>'; };
        function MoreEnd() { return '</div>'; };
        function MoreToggle(v) { QV('idx_dlgMoreButtons1',!v); QV('idx_dlgMoreButtons2',v); QV('idx_dlgMoreButtons3',v); }
        function getSelectedOptions(sel) { var opts = [], opt; for (var i = 0, len = sel.options.length; i < len; i++) { opt = sel.options[i]; if (opt.selected) { opts.push(opt.value); } } return opts; }
        function getInstance(x, y) { for (var i in x) { if (x[i]['InstanceID'] == y) return x[i]; } return null; }
        function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
        function guidToStr(g) { return g.substring(6, 8) + g.substring(4, 6) + g.substring(2, 4) + g.substring(0, 2) + '-' + g.substring(10, 12) + g.substring(8, 10) + '-' + g.substring(14, 16) + g.substring(12, 14) + '-' + g.substring(16, 20) + '-' + g.substring(20); }
        function getUrlVars() { var j, hash, vars = [], hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for (var i = 0; i < hashes.length; i++) { j = hashes[i].indexOf('='); if (j > 0) { vars[hashes[i].substring(0, j)] = hashes[i].substring(j + 1, hashes[i].length); } } return vars; }
        //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 addHtmlValue(t, v) { return '<div style=height:20px><div style=float:right;width:220px><b>' + v + '</b></div><div>' + t + '</div></div>'; }
        function addHtmlValue(t, v) { return '<table><td style=width:120px>' + t + '<td><b>' + v + '</b></table>'; }
        function addHtmlValue2(t, v) { return '<div><div style=display:inline-block;float:right>' + v + '</div><div style=display:inline-block>' + t + '</div></div>'; }
        function addHtmlValue3(t, v) { return '<div><b>' + t + '</b></div><div style=margin-left:16px>' + v + '</div>'; }
        function addHtmlValue4(t, v) { return '<table style=width:100%><td style=width:120px>' + t + '<td style=text-align:right><b>' + v + '</b></table>'; }
        function addHtmlValue5(t, v) { return '<div style=padding:4px><div style=display:inline-block;float:right><b>' + v + '</b></div><div style=display:inline-block>' + t + '</div></div>'; }
        function focusTextBox(x) { setTimeout(function(){ Q(x).selectionStart = Q(x).selectionEnd = 65535; Q(x).focus(); }, 0); }
        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 isPrivateIP(a) { return (a.startsWith('10.') || a.startsWith('172.16.') || a.startsWith('192.168.')); }
        function u2fSupported() { return (window.u2f && ((navigator.userAgent.indexOf('Chrome/') > 0) || (navigator.userAgent.indexOf('Firefox/') > 0) || (navigator.userAgent.indexOf('Opera/') > 0) || (navigator.userAgent.indexOf('Safari/') > 0))); }
        function findOne(arr1, arr2) { if ((arr1 == null) || (arr2 == null)) return false; return arr2.some(function (v) { return arr1.indexOf(v) >= 0; }); };
        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(); }
        function copyTextToClip2(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 = decodeURIComponent(txt); document.body.appendChild(e); selectElementText(e); document.execCommand('copy'); e.remove(); }
        function capitalizeFirstLetter(x) { return x.charAt(0).toUpperCase() + x.slice(1); }
        function printDate(d) { return d.toLocaleDateString(args.locale); }
        function printTime(d) { return d.toLocaleTimeString(args.locale); }
        function printDateTime(d) { return d.toLocaleString(args.locale); }
        function printFlexDateTime(d) { if (printDate(new Date()) == printDate(d)) { return printTime(d); } else { return printDateTime(d); } }
        function addDetailItem(title, value, state) { return '<table style=width:100%><td>' + nobreak(title) + '<td style=text-align:right>' + value + '</table>'; }
        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; }); };
        function addTextLink(subtext, text, link) { var i = text.toLowerCase().indexOf(subtext.toLowerCase()); if (i == -1) { return text; } return text.substring(0, i) + '<a href="' + link + '">' + subtext + '</a>' + text.substring(i + subtext.length); }
        function getOrderedList(objList, oname) { var r = []; for (var i in objList) { r.push(objList[i]); } r.sort(function(a, b) { var aa = a[oname].toLowerCase(), bb = b[oname].toLowerCase(); if (aa > bb) return 1; if (aa < bb) return -1; return 0; }); return r; }
        function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); }
        function nobreak(x) { return x.split(' ').join('&nbsp;'); }
        function pad2(num) { var s = '00' + num; return s.substr(s.length - 2); }
        function encodeURIComponentEx(txt) { return encodeURIComponent(txt).replace(/'/g,'%27'); };
        function getUserName(userid) {
            var useridsplit = userid.split('/'), userid2 = useridsplit[0] + '/' + useridsplit[1] + '/' + useridsplit[2], guestname = '';
            if ((useridsplit.length == 4) && (useridsplit[3].startsWith('guest:'))) { guestname = ' - ' + decode_utf8(atob(useridsplit[3].substring(6))); }
            if (users && users[userid2] != null) { if (users[userid2].realname != null) return (users[userid2].realname + guestname); else return (users[userid2].name + guestname); }
            return (useridsplit[2] + guestname);
        }
        function round(value, precision) { var multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; }
        function safeNewWindow(url, target) { var newWindow = window.open(url, target, 'noopener,noreferrer'); if (newWindow) { newWindow.opener = null; } }
        function isWindowsNode(node) { if ((node.mtype != 2) || (node.agent == null) || (node.agent.id == null)) return false; return ([1,2,3,4,21,22,34].indexOf(node.agent.id) >= 0); }

        // Webkit seems to have a problem with "download" tag causing "network error", but openning the download in a hidden frame fixes it.
        // So we do that for all browsers except FireFox
        function downloadFile(link, name, closeDialog) {
            var element = document.createElement('a');
            element.setAttribute('href', link);
            element.setAttribute('rel', 'noreferrer noopener');
            element.setAttribute('target', 'fileDownloadFrame');
            if (navigator.userAgent.indexOf('Firefox') >= 0) { element.setAttribute('download', decodeURIComponent(name?name:'')); }
            document.body.appendChild(element);
            element.click();
            document.body.removeChild(element);
            if (closeDialog) { setDialogMode(0); }
        }

        // Make the dialog box movable
        function dialogBoxDrag() {
            var elmnt = Q('dialog');
            var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
            Q('dialogHeader').onmousedown = dragMouseDown;
            function dragMouseDown(e) {
                e = e || window.event;
                e.preventDefault();
                pos3 = e.clientX;
                pos4 = e.clientY;
                document.onmouseup = closeDragElement;
                document.onmousemove = elementDrag;
            }
            function elementDrag(e) {
                e = e || window.event;
                e.preventDefault();
                pos1 = pos3 - e.clientX;
                pos2 = pos4 - e.clientY;
                pos3 = e.clientX;
                pos4 = e.clientY;
                elmnt.style.top = (elmnt.offsetTop - pos2) + 'px';
                elmnt.style.left = (elmnt.offsetLeft - pos1) + 'px';
            }
            function closeDragElement() {
                document.onmouseup = null;
                document.onmousemove = null;
            }
        }

        // Request Confirmation if closing while a desktop, terminal session is active
        window.addEventListener('beforeunload', function (e) {
            if (((desktop != null) && (xxcurrentView == 11)) || ((terminal != null) && (xxcurrentView == 12))) { e.preventDefault(); e.returnValue = ''; }
        });

    </script>
</body>
</html>
    at new HTMLParser (/opt/meshcentral/node_modules/html-minifier/src/htmlparser.js:244:13)
    at minify (/opt/meshcentral/node_modules/html-minifier/src/htmlminifier.js:980:3)
    at exports.minify (/opt/meshcentral/node_modules/html-minifier/src/htmlminifier.js:1341:16)
    at Object.startEx (/opt/meshcentral/node_modules/meshcentral/translate/translate.js:508:31)
    at CreateMeshCentralServer.obj.Start (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:240:41)
    at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4147:24
    at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
    at /opt/meshcentral/node_modules/meshcentral/meshcentral.js:4144:9
    at InstallModules (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3894:178)
    at mainStart (/opt/meshcentral/node_modules/meshcentral/meshcentral.js:3978:5)

Node.js v18.19.0

Is what I get when passing in node node_modules/meshcentral --translate. I have a default MeshCentral install, with the exception of a custom UI under meshcentral-web

si458 commented 5 months ago

@DaanSelen the must be some value or string inside your custom file that it just doesnt like! try renaming your custom file to default.handlebars.backup, rerun the --translate and see if it translates ok if it does, then rename ur file back and run again, if it then errors out, the is something inside the default.handlebars of your file it just doesnt like! and im guessing it must be around

} catch (ex) {}
                meshserver.send({ action: 'userWebState', state: JSON.stringify(s) });
DaanSelen commented 5 months ago

then rename ur file back and run again, if it then errors out, the is something inside the default.handlebars of your file it just doesnt like! and im guessing it must be around

} catch (ex) {}

Your fix for translating correctly. When I move it as backup file it works, but how can I troubleshoot where it errors?

si458 commented 5 months ago

so if you renamed the file to .backup and its translating ok BUT then rename your file back and its NOT translating ok, then the is something wrong in your file

its going to be very hard to work out what its not working?

if your happy to, email me the file and ill have a quick dig https://github.com/si458 -> email on left!

DaanSelen commented 5 months ago

Also something, I don't know if this is related. But after removing the custom meshcentral-web folder and moving it outside its scope, then restarting meshcentral does not fix the Old returning:

image

The Desktop and Terminal and files tab is not present. This should all be a default Meshcentral installation

si458 commented 5 months ago

@DaanSelen Sorry for the delay, Mad day! Lines 1724 and 1746 of ur file u sent you have double arrows <<input which is causing the html to be phased incorrectly! It should only be <input Also the default.handlebars files was updated last month in the latest release (last week if using the master image), so ur behind by 5 months on changes in code https://github.com/Ylianst/MeshCentral/blob/1.1.24/views/default.handlebars

DaanSelen commented 5 months ago

Not related to this issue, thanks for your work though Simon! Regarding: https://github.com/Ylianst/MeshCentral/issues/5496 is there currently any plans for UI changes?