1
0
Fork 0
mirror of https://github.com/Ylianst/MeshCentral.git synced 2025-03-09 15:40:18 +00:00

Compare commits

..

No commits in common. "master" and "MeshCentral_v1.0.75" have entirely different histories.

441 changed files with 32661 additions and 127560 deletions

View file

@ -49,7 +49,7 @@ Add any other context about the problem here.
**Your config.json file** **Your config.json file**
``` ```
{ {
"$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json", "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
"__comment1__": "This is a simple configuration file, all values and sections that start with underscore (_) are ignored. Edit a section and remove the _ in front of the name. Refer to the user's guide for details.", "__comment1__": "This is a simple configuration file, all values and sections that start with underscore (_) are ignored. Edit a section and remove the _ in front of the name. Refer to the user's guide for details.",
"__comment2__": "See node_modules/meshcentral/sample-config-advanced.json for a more advanced example.", "__comment2__": "See node_modules/meshcentral/sample-config-advanced.json for a more advanced example.",
"settings": { "settings": {

View file

@ -1,8 +1,5 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: Question
url: https://github.com/Ylianst/MeshCentral/discussions
about: Ask a question in discussions.
- name: Unofficial Discord Server - name: Unofficial Discord Server
url: https://discord.gg/8wHC6ASWAc url: https://discord.gg/8wHC6ASWAc
about: Please ask here for support questions. about: Please ask here for support questions.

68
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View file

@ -0,0 +1,68 @@
---
name: Question
about: Create a question for community help
title: ''
labels: question
assignees: ''
---
**Describe your issue**
A clear and concise description of what your issue is.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Server Software (please complete the following information):**
- OS: [e.g. Ubuntu]
- Virtualization: [e.g. Docker]
- Network: [e.g. LAN/WAN, reverse proxy, cloudflare, ssl offload, etc...]
- Version: [e.g. 1.0.43]
- Node: [e.g. 18.4.0]
**Client Device (please complete the following information):**
- Device: [e.g. Laptop]
- OS: [e.g. Ubuntu]
- Network: [e.g. Local to Meshcentral, Remote over WAN]
- Browser: [e.g. Google Chrome]
- MeshCentralRouter Version: [if applicable]
**Remote Device (please complete the following information):**
- Device: [e.g. Laptop]
- OS: [e.g. Windows 10 21H2]
- Network: [e.g. Local to Meshcentral, Remote over WAN]
- Current Core Version (if known): [**HINT**: Go to a device then `console` Tab then type `info`]
**Your config.json file**
```
{
"$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
"__comment1__": "This is a simple configuration file, all values and sections that start with underscore (_) are ignored. Edit a section and remove the _ in front of the name. Refer to the user's guide for details.",
"__comment2__": "See node_modules/meshcentral/sample-config-advanced.json for a more advanced example.",
"settings": {
"_cert": "myserver.mydomain.com",
"_WANonly": true,
"_LANonly": true,
"_sessionKey": "MyReallySecretPassword1",
"_port": 443,
"_aliasPort": 443,
"_redirPort": 80,
"_redirAliasPort": 80
},
"domains": {
"": {
"_title": "MyServer",
"_title2": "Servername",
"_minify": true,
"_newAccounts": true,
"_userNameIsEmail": true
}
},
"_letsencrypt": {
"__comment__": "Requires NodeJS 8.x or better, Go to https://letsdebug.net/ first before trying Let's Encrypt.",
"email": "myemail@mydomain.com",
"names": "myserver.mydomain.com",
"production": false
}
}
```

View file

@ -13,7 +13,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
# We must fetch at least the immediate parents so that if this is # We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head. # a pull request then we can checkout the head.
@ -26,7 +26,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages # Override language selection by uncommenting this and choosing your languages
# with: # with:
# languages: go, javascript, csharp, python, cpp, java # languages: go, javascript, csharp, python, cpp, java
@ -48,4 +48,4 @@ jobs:
# make release # make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v1

View file

@ -14,8 +14,8 @@ jobs:
deploy: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v2
- uses: actions/setup-python@v5 - uses: actions/setup-python@v2
with: with:
python-version: 3.x python-version: 3.x
- run: pip install --upgrade pip - run: pip install --upgrade pip

View file

@ -1,67 +1,55 @@
name: Docker name: Docker
on: on:
push:
branches:
- master
release: release:
types: [published] types: [published]
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }} IMAGE_NAME: ${{ github.repository }}
jobs: jobs:
check-token: check-token:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
token_defined: ${{ steps.token_check.outputs.token_defined }} token: ${{ steps.token.outputs.defined }}
steps: steps:
- name: Check token - id: token
id: token_check
env: env:
MY_TOKEN: ${{ secrets.MY_TOKEN }} MY_TOKEN: ${{ secrets.MY_TOKEN }}
if: "${{ env.MY_TOKEN != '' }}" if: "${{ env.MY_TOKEN != '' }}"
run: echo "token_defined=true" >> "$GITHUB_OUTPUT" run: echo "::set-output name=defined::true"
build: build:
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [check-token] needs: [check-token]
if: needs.check-token.outputs.token_defined == 'true' if: needs.check-token.outputs.token == 'true'
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v2
- name: Log in to the Container registry - name: Log in to the Container registry
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.MY_TOKEN }} password: ${{ secrets.MY_TOKEN }}
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
uses: docker/metadata-action@v5 uses: docker/metadata-action@v4
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image - name: Build and push Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v2
with: with:
context: . context: .
file: docker/Dockerfile file: docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
build-args: | build-args: |
INCLUDE_MONGODBTOOLS=true INCLUDE_MONGODBTOOLS=true
PREINSTALL_LIBS=true PREINSTALL_LIBS=true

View file

@ -3,8 +3,6 @@ on:
push: push:
branches: branches:
- master - master
paths:
- 'package.json'
jobs: jobs:
build: build:
@ -12,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Release - name: Release

2
.gitignore vendored
View file

@ -10,12 +10,12 @@
[Aa]gents/meshcore.min.js [Aa]gents/meshcore.min.js
[Pp]ublic/translations/ [Pp]ublic/translations/
[Vv]iews/translations/ [Vv]iews/translations/
[Ee]mails/translations/
[Pp]ublic/*-min.htm [Pp]ublic/*-min.htm
[Vv]iews/*-min.handlebars [Vv]iews/*-min.handlebars
meshcentral.db meshcentral.db
meshcentral.db.json meshcentral.db.json
mesherrors.txt mesherrors.txt
package-lock.json
bob.json bob.json
.greenlockrc .greenlockrc

2
.npmrc
View file

@ -1 +1 @@
engine-strict = true engine-strict=true

388
.vscode/settings.json vendored
View file

@ -1,12 +1,7 @@
{ {
"cSpell.words": [ "cSpell.words": [
"abcdf", "abcdf",
"accountchange",
"accountcreate",
"accountid", "accountid",
"accountremove",
"acebase",
"acmd",
"acmepath", "acmepath",
"actiontype", "actiontype",
"adddevicegroup", "adddevicegroup",
@ -21,30 +16,17 @@
"addusertousergroup", "addusertousergroup",
"adminaccount", "adminaccount",
"adminname", "adminname",
"agentaliasdns",
"agentaliasport",
"agentallowedip", "agentallowedip",
"agentapp",
"agentblockedip", "agentblockedip",
"agentconfig", "agentconfig",
"agentconsole", "agentconsole",
"agentcoredump",
"agentcoredumpusers",
"agentcustomization", "agentcustomization",
"agentdownload", "agentdownload",
"agenterrorlogs", "agenterrorlogs",
"agentid",
"agentidletimeout", "agentidletimeout",
"agentinfo",
"agentinvite",
"agentinvitecodes",
"agentkey", "agentkey",
"Agentless", "Agentless",
"agentnoproxy", "agentnoproxy",
"agentport",
"agentportbind",
"agentporttls",
"agenttransfer",
"agenttype", "agenttype",
"agentupdateblocksize", "agentupdateblocksize",
"agentupdatetest", "agentupdatetest",
@ -52,97 +34,57 @@
"aliasport", "aliasport",
"allevents", "allevents",
"allowaccountreset", "allowaccountreset",
"allowframing",
"allowfullscreen", "allowfullscreen",
"allowhighqualitydesktop",
"allowsavingdevicecredentials",
"allusers",
"alreadyinstalled", "alreadyinstalled",
"amtacmactivation", "amtacmactivation",
"amtevents",
"amthost",
"amtmanager", "amtmanager",
"amtoff", "amtoff",
"amton", "amton",
"amtonly", "amtonly",
"amtpass",
"amtreset", "amtreset",
"amtscanner", "amtscanner",
"amtscanoptions",
"anewaccountcaptcha",
"apassword",
"apasswordhint",
"apikey", "apikey",
"apos",
"appmetrics", "appmetrics",
"apprelays",
"ashx", "ashx",
"assistantconfig",
"assistantcustomization",
"assistantnoproxy",
"atag", "atag",
"authcookie", "authcookie",
"authenticode", "authenticode",
"authfail",
"authlog", "authlog",
"authlogfile", "authlogfile",
"Authn", "Authn",
"authorizationurl",
"authstr",
"authstrategies",
"autofido", "autofido",
"awsrds", "awsrds",
"backgroundcolor",
"backgroundonly", "backgroundonly",
"backupcode", "backupcode",
"backuppath", "backuppath",
"badargs",
"badtlscert",
"bancommonpasswords",
"batchupload",
"bitmask", "bitmask",
"Bounser",
"callbackurl", "callbackurl",
"captchaargs",
"ccmp", "ccmp",
"Centralv", "Centralv",
"certbot", "certbot",
"certfiles", "certfiles",
"certhash",
"certkeyhash",
"certpfx", "certpfx",
"certpfxpass", "certpfxpass",
"certurl", "certurl",
"cfile", "cfile",
"changedevice", "changedevice",
"changenode", "changenode",
"changepassword",
"chatnotify", "chatnotify",
"checkemail",
"checkmail",
"chnl",
"CIRA", "CIRA",
"ciraconn",
"ciralocalfqdn", "ciralocalfqdn",
"ckey", "ckey",
"clearpower", "clearpower",
"clientid", "clientid",
"clientsecret", "clientsecret",
"clipboardget",
"clipboardset",
"cmdoptions",
"cmds", "cmds",
"cnonce",
"companyname", "companyname",
"configfile", "configfile",
"configfiles", "configfiles",
"configkey", "configkey",
"connectionstring", "connectionstring",
"Consts",
"cookieipcheck", "cookieipcheck",
"cookiesamesite", "cookiesamesite",
"coolofftime", "coolofftime",
"coredump",
"coredumps", "coredumps",
"createaccount", "createaccount",
"createmesh", "createmesh",
@ -150,14 +92,8 @@
"crowdsec", "crowdsec",
"crypted", "crypted",
"cscli", "cscli",
"curloptionshttp",
"curloptionshttps",
"cuser", "cuser",
"cuserid",
"customui",
"datafile",
"datapath", "datapath",
"datas",
"datastr", "datastr",
"dbconfig", "dbconfig",
"dbdeleteconfigfiles", "dbdeleteconfigfiles",
@ -171,119 +107,67 @@
"dbpulldatafiles", "dbpulldatafiles",
"dbpushconfigfiles", "dbpushconfigfiles",
"dbshowconfigfile", "dbshowconfigfile",
"debuglevel",
"defaultuserwebstate", "defaultuserwebstate",
"deldump",
"deleteaccount",
"deletedefaultdomain", "deletedefaultdomain",
"deletedomain", "deletedomain",
"deletemesh", "deletemesh",
"deleteuser", "deleteuser",
"deleteusergroup", "deleteusergroup",
"deluser",
"deluserpath",
"DESKLIMITEDINPUT",
"desktopmultiplex",
"desktopnotify", "desktopnotify",
"desktopprivacybar", "desktopprivacybar",
"desktopprompt", "desktopprompt",
"desktoprelays",
"desktopviewonly", "desktopviewonly",
"devbox", "devbox",
"devicefile",
"deviceid", "deviceid",
"deviceinfo", "deviceinfo",
"deviceinfocount", "deviceinfocount",
"devicemessage", "devicemessage",
"deviceopenurl", "deviceopenurl",
"devicepower", "devicepower",
"devicepowerevents",
"devicesearchbarserverandclientname",
"deviceshare",
"devicesharing", "devicesharing",
"devicetoast", "devicetoast",
"devid", "devid",
"Digesthash",
"disablerequestedauthncontext",
"displayname", "displayname",
"dlccore",
"dlcore",
"dldump",
"dnscount",
"dnssuffix", "dnssuffix",
"domaindefaults", "domaindefaults",
"domainid", "domainid",
"domainname",
"domainurl",
"domainx",
"dont", "dont",
"dontlognull", "dontlognull",
"downloadfile",
"dumpcores", "dumpcores",
"dumpfile",
"editdevice", "editdevice",
"editdevicegroup", "editdevicegroup",
"editgroup", "editgroup",
"editmesh", "editmesh",
"edituser", "edituser",
"emailaddress",
"emailcheck",
"emaildomain",
"emailexists", "emailexists",
"emailok",
"emailvalidation",
"emailvalidationrequired",
"emailverified", "emailverified",
"entityid", "entityid",
"entrypoints", "entrypoints",
"errdesc",
"errlogpath", "errlogpath",
"esversion", "esversion",
"etype", "etype",
"eventlogger", "eventlogger",
"exactport", "exactport",
"exactports", "exactports",
"exphbs",
"extractall", "extractall",
"extrakey",
"extralinks", "extralinks",
"extrascriptsrc",
"factorauth",
"factorwarning",
"fadev",
"fahold",
"fasent",
"fastcert", "fastcert",
"fchallenge",
"fileaccess", "fileaccess",
"filedata",
"filefullpath",
"filenotify", "filenotify",
"fileprompt", "fileprompt",
"filesize",
"filespath", "filespath",
"filestats",
"fileurl",
"filteredusers", "filteredusers",
"filterid", "filterid",
"firebaserelay", "firebaserelay",
"firstname", "firstname",
"forceduserwebstate", "forceduserwebstate",
"foregroundcolor",
"forwardclient",
"forwardfor", "forwardfor",
"forwardwrite",
"forwardwsocket",
"fpath",
"Freemonitoring", "Freemonitoring",
"frontends", "frontends",
"ftarget",
"fullpath",
"fullrights", "fullrights",
"fullscreen", "fullscreen",
"gatewaymac", "gatewaymac",
"generateinvitelink", "generateinvitelink",
"geourl",
"getnetworkinfo", "getnetworkinfo",
"getsysinfo", "getsysinfo",
"getwspass", "getwspass",
@ -291,85 +175,49 @@
"gotodevicename", "gotodevicename",
"gotonode", "gotonode",
"groupid", "groupid",
"guestdevicesharing",
"guestname", "guestname",
"GUESTSHARING",
"hashhex",
"Hashi", "Hashi",
"hashpass", "hashpass",
"hashpasssplit", "hashpasssplit",
"hashpassword", "hashpassword",
"Hashs",
"healthcheck", "healthcheck",
"Hilaire", "Hilaire",
"hkey",
"httpheaders", "httpheaders",
"httplog", "httplog",
"httpport",
"hwchallenge",
"hwotp",
"hwstate",
"hwtoken",
"Ider",
"idexists", "idexists",
"idhex", "idhex",
"idpurl", "idpurl",
"idsplit",
"iframe", "iframe",
"ignoreagenthashcheck", "ignoreagenthashcheck",
"iishash",
"imagebase",
"imagefile",
"indexagenterrorlog", "indexagenterrorlog",
"indexmcrec", "indexmcrec",
"installflags",
"installsize",
"installtext", "installtext",
"intelamt", "intelamt",
"interactiveonly", "interactiveonly",
"interuser", "interuser",
"invitecodes", "invitecodes",
"ipaddr",
"ipblockeduserredirect",
"ipcheck",
"ipex",
"ipkvm", "ipkvm",
"iplayer", "iplayer",
"ipranges", "ipranges",
"isaml",
"Jitsi", "Jitsi",
"jumpcloud", "jumpcloud",
"keyfile", "keyfile",
"keygrip",
"keyid",
"lanonly", "lanonly",
"LAPI", "LAPI",
"lastaddr", "lastaddr",
"lastconnect", "lastconnect",
"lastname", "lastname",
"ldapauth", "ldapauth",
"ldapobj",
"ldapoptions", "ldapoptions",
"ldapsaveusertofile",
"ldapsyncwithusergroups",
"ldapuserbinarykey", "ldapuserbinarykey",
"ldapuseremail", "ldapuseremail",
"ldapusergroups",
"ldapuserimage",
"ldapuserkey",
"ldapusername", "ldapusername",
"ldapuserphonenumber",
"ldapuserrealname",
"ldapuserrequiredgroupmembership",
"ldapusers", "ldapusers",
"leok", "leok",
"letsencrypt", "letsencrypt",
"lightgray",
"limiteddesktop", "limiteddesktop",
"limitedevents", "limitedevents",
"LIMITEVENTS",
"Linaro", "Linaro",
"linuxpath",
"listdevicegroups", "listdevicegroups",
"listdevices", "listdevices",
"listdomains", "listdomains",
@ -380,93 +228,56 @@
"listusersessions", "listusersessions",
"listusersofdevicegroup", "listusersofdevicegroup",
"loadconfigfromdb", "loadconfigfromdb",
"localdiscovery",
"localfile", "localfile",
"localpath", "localpath",
"localrelay",
"localsessionrecording",
"localurl", "localurl",
"lockagentdownload", "lockagentdownload",
"locksettings", "locksettings",
"logfile",
"logincodeb",
"logindomain", "logindomain",
"loginfooter", "loginfooter",
"loginkey", "loginkey",
"loginkeyfile", "loginkeyfile",
"loginlogo",
"loginmode",
"loginpass", "loginpass",
"loginpicture",
"loginscreen",
"logintoken", "logintoken",
"logintokengen", "logintokengen",
"logintokenkey", "logintokenkey",
"logintokens", "logintokens",
"loginuser", "loginuser",
"logoback", "logoback",
"logoutcontrols",
"logouturl", "logouturl",
"macrouter",
"magenturl",
"mailserver", "mailserver",
"mailtokengen", "mailtokengen",
"maintenancemode", "maintenancemode",
"mainwelcome",
"MANAGECOMPUTERS",
"managedevices", "managedevices",
"manageusers", "manageusers",
"markcoredump",
"maxfidokeys", "maxfidokeys",
"maxlen", "maxlen",
"maxuseraccounts",
"mcpath", "mcpath",
"mcrdesktop", "mcrdesktop",
"mcrec", "mcrec",
"mcrfiles", "mcrfiles",
"mcrouter",
"Mebx", "Mebx",
"meshaction",
"meshadmin", "meshadmin",
"meshagent", "meshagent",
"meshagents", "meshagents",
"meshauth", "meshauth",
"meshcentral", "meshcentral",
"meshcentralhost", "meshcentralhost",
"meshchange",
"meshcmd", "meshcmd",
"meshcommander", "meshcommander",
"meshcookie",
"meshcore", "meshcore",
"meshctrl", "meshctrl",
"meshdesktopmultiplex",
"meshdevicefile",
"mesherrorlogpath",
"mesherrors", "mesherrors",
"meshfilename",
"meshid", "meshid",
"meshidhex",
"meshidname", "meshidname",
"meshinstall",
"meshmail", "meshmail",
"meshmessenger",
"meshmessengerid",
"meshmessengerpicture",
"meshmessengertitle",
"meshname", "meshname",
"meshosxagent",
"meshquota", "meshquota",
"meshrelay", "meshrelay",
"MESHRIGHT",
"meshrights", "meshrights",
"meshscanner", "meshscanner",
"meshserver",
"meshsettings",
"meshsettingslines",
"meshtype", "meshtype",
"meshuser",
"Messagebox", "Messagebox",
"messageid",
"Messenging", "Messenging",
"minfo", "minfo",
"minifyall", "minifyall",
@ -476,25 +287,17 @@
"mongorestore", "mongorestore",
"moutput", "moutput",
"movetodevicegroup", "movetodevicegroup",
"mpkg",
"mpsaliasport", "mpsaliasport",
"mpscert", "mpscert",
"mpsdebug", "mpsdebug",
"mpspass",
"mpsport", "mpsport",
"mpsserver", "mpsserver",
"mpsservers", "mpsservers",
"MPSSSL", "MPSSSL",
"mpstlsoffload",
"mqttbroker", "mqttbroker",
"MSCHA", "MSCHA",
"msgid",
"mstsc", "mstsc",
"mstscrelay",
"mtype",
"multiplexor",
"multiresponse", "multiresponse",
"multivalued",
"myaccountname", "myaccountname",
"mycompany", "mycompany",
"mydomain", "mydomain",
@ -506,19 +309,13 @@
"netif", "netif",
"newaccountemaildomains", "newaccountemaildomains",
"newaccountname", "newaccountname",
"newaccountrealms",
"newaccounts", "newaccounts",
"newaccountscaptcha",
"newaccountspass", "newaccountspass",
"newaccountsrights", "newaccountsrights",
"newaccountsusergroups",
"newgroupname", "newgroupname",
"newobj", "newobj",
"newpass",
"newpassword", "newpassword",
"NGNIX", "NGNIX",
"nightmode",
"noact",
"noagentupdate", "noagentupdate",
"noamt", "noamt",
"noauth", "noauth",
@ -527,92 +324,47 @@
"nodecount", "nodecount",
"nodeid", "nodeid",
"nodeids", "nodeids",
"nodeidsplit",
"nodeinfo", "nodeinfo",
"nodekey",
"nodepath", "nodepath",
"NODESKTOP",
"nodewindows", "nodewindows",
"nofiles", "nofiles",
"nofirewall", "nofirewall",
"nolog",
"nologout",
"NOMESHCMD",
"nominify", "nominify",
"nonalpha", "nonalpha",
"NONEWDEVICES",
"nonewgroups", "nonewgroups",
"noproxy",
"noredirect",
"nosniff",
"noterminal", "noterminal",
"notools", "notools",
"nouser",
"nousers", "nousers",
"novnc", "novnc",
"npmjs", "npmjs",
"npmpath", "npmpath",
"npmproxy", "npmproxy",
"npmtag", "npmtag",
"objid",
"ODELAY", "ODELAY",
"offloader", "offloader",
"offloaders", "offloaders",
"oidc", "oidc",
"oldpassword",
"oldpasswordban",
"oldpasswords",
"oneclickrecovery",
"onlyselecteddevicegroups",
"onlyselectedusers",
"openidconnect",
"openstreetmap",
"openurl", "openurl",
"orphanagentuser", "orphanagentuser",
"osdesc", "osdesc",
"osinfo", "osinfo",
"otpdev",
"otpekey",
"otpemail",
"otphkeys", "otphkeys",
"otpkeys", "otpkeys",
"otplib",
"otppush",
"otpsecret", "otpsecret",
"otpsms",
"parentpath", "parentpath",
"passchange",
"passhint",
"passlogin",
"passrequirementstr",
"passtype",
"passwordrequirements", "passwordrequirements",
"passwordrequirementsstr",
"pastlogin",
"pathx",
"peinfo",
"phonenumber",
"PKCK", "PKCK",
"plivo", "plivo",
"pluginadmin",
"plusplus", "plusplus",
"portbind",
"postflight",
"poweraction", "poweraction",
"powerevents", "powerevents",
"Preconfigured",
"Proto", "Proto",
"publicid", "publicid",
"pushlogin",
"pushrelay",
"pushrelayserver",
"qport",
"randompass", "randompass",
"Raritan", "Raritan",
"rauth", "rauth",
"rawdata", "rawdata",
"rcookie", "rcookie",
"rdpport",
"realname", "realname",
"recordencryptionrecode", "recordencryptionrecode",
"recordpath", "recordpath",
@ -621,21 +373,11 @@
"redirections", "redirections",
"redirport", "redirport",
"redirserver", "redirserver",
"refreshtoken",
"relayaliasport",
"relaydns", "relaydns",
"relayid",
"relayport", "relayport",
"relayserver",
"relaysession",
"remembertoken",
"remoteaddr",
"remoteaddrport",
"REMOTECOMMAND",
"remotecontrol", "remotecontrol",
"remotefile", "remotefile",
"remotepath", "remotepath",
"REMOTEVIEWONLY",
"removeallusersfromusergroup", "removeallusersfromusergroup",
"removedevicegroup", "removedevicegroup",
"removedomain", "removedomain",
@ -650,21 +392,11 @@
"removeuserfromusergroup", "removeuserfromusergroup",
"removeusergroup", "removeusergroup",
"resetaccount", "resetaccount",
"RESETOFF",
"resetpass", "resetpass",
"responseid", "responseid",
"restoreserver",
"rightsstr", "rightsstr",
"rname", "rname",
"rnamel", "rnamel",
"rootcert",
"rootredirect",
"rpassword",
"rpasswordhint",
"rport",
"rtpass",
"rtuser",
"runas",
"runasuser", "runasuser",
"runasuseronly", "runasuseronly",
"runcommand", "runcommand",
@ -672,43 +404,23 @@
"runmode", "runmode",
"runonservererror", "runonservererror",
"runonserverupdated", "runonserverupdated",
"ruserid",
"sameorigin",
"selfupdate", "selfupdate",
"selfurl",
"senderid", "senderid",
"sendgrid", "sendgrid",
"sendinviteemail", "sendinviteemail",
"serialtunnel",
"SERVERBACKUP",
"serverfeatures",
"serverfiles", "serverfiles",
"serverhttps",
"serverid", "serverid",
"serveridhex",
"serverinfo", "serverinfo",
"serverkey", "serverkey",
"servername", "servername",
"servernoproxy",
"serverpath",
"serverpic",
"serverport",
"SERVERRESTORE",
"servertlshash",
"serverupdate", "serverupdate",
"servicename", "servicename",
"servicepath", "servicepath",
"sessioncode",
"sessionkey", "sessionkey",
"sessionrecording", "sessionrecording",
"sessionsamesite",
"sessiontime", "sessiontime",
"setbad",
"SETNOTES",
"settodomain", "settodomain",
"sftpconnect",
"shareid", "shareid",
"showagents",
"showall", "showall",
"showallmeshes", "showallmeshes",
"showevents", "showevents",
@ -716,31 +428,20 @@
"showitem", "showitem",
"showmeshes", "showmeshes",
"shownodes", "shownodes",
"showpasswordlogin",
"showpower", "showpower",
"showsmbios", "showsmbios",
"showusergroups", "showusergroups",
"showusers", "showusers",
"showversion",
"siteadmin", "siteadmin",
"SITERIGHT",
"sitestyle", "sitestyle",
"smsserver", "smsserver",
"specificupdate", "specificupdate",
"splitip", "splitip",
"splitpath",
"spliturl",
"srights", "srights",
"sshconnect",
"sshfilesrelay",
"sshport",
"sshrelay",
"sshterminalrelay",
"ssid", "ssid",
"sspi", "sspi",
"startack", "startack",
"statsevents", "statsevents",
"stricttransportsecurity",
"Strs", "Strs",
"subdir", "subdir",
"swarmallowedip", "swarmallowedip",
@ -750,173 +451,86 @@
"syslogauth", "syslogauth",
"syslogjson", "syslogjson",
"syslogtcp", "syslogtcp",
"tcpport",
"telnyx", "telnyx",
"temail",
"tenantid", "tenantid",
"terminalnotify", "terminalnotify",
"terminalprompt", "terminalprompt",
"termsize", "termsize",
"timedoc",
"titleid",
"titlepicture", "titlepicture",
"tkip", "tkip",
"tlscertcheck", "tlscertcheck",
"tlshash",
"tlsock",
"tlsoffload", "tlsoffload",
"tlsoptions",
"tlsrootcert", "tlsrootcert",
"tlsstrict", "tlsstrict",
"tmpdl",
"tokenemail",
"tokenlogin",
"tokenpassword",
"tokenpush",
"tokenrequired", "tokenrequired",
"tokensms",
"tokenurl",
"tokenuserid",
"tokenusername",
"totalsize",
"TOTP",
"tpass",
"tpassword",
"tpush",
"traefik", "traefik",
"translateall", "translateall",
"translationpath", "translationpath",
"trustedcert", "trustedcert",
"trustedproxy", "trustedproxy",
"tsms",
"TTLS", "TTLS",
"tunnelws", "tunnelws",
"tunnelwsstate", "tunnelwsstate",
"tuser",
"tuserid",
"tusername",
"twofactor",
"twofactorcookiedurationdays",
"twofactortimeout",
"tzoffset", "tzoffset",
"uaparser",
"ucookie",
"ugroup", "ugroup",
"ugroups", "ugroups",
"ugrp", "ugrp",
"ugrpid", "ugrpid",
"uicustomevent", "uicustomevent",
"unadmin", "unadmin",
"unknownuserrootredirect",
"unsealkey", "unsealkey",
"updatefiles",
"uploadack", "uploadack",
"uploaderror", "uploaderror",
"uploadfile",
"uploadfilebatch",
"uploadmeshcorefile",
"uploadstart", "uploadstart",
"urlpath",
"urlswitching",
"useid", "useid",
"userallowedip", "userallowedip",
"userblockedip", "userblockedip",
"userbroadcast", "userbroadcast",
"userconsentflags", "userconsentflags",
"usercount", "usercount",
"userex",
"userfiles",
"userfirst",
"usergroupchange",
"usergroups", "usergroups",
"userid", "userid",
"userids", "userids",
"userimage",
"userinfourl",
"usernameisemail", "usernameisemail",
"userquota", "userquota",
"userrequiredhttpheader",
"Usersessionidletimeout", "Usersessionidletimeout",
"usersid",
"usersplit",
"vaultdeleteconfigfiles", "vaultdeleteconfigfiles",
"vaultpullconfigfiles", "vaultpullconfigfiles",
"vaultpushconfigfiles", "vaultpushconfigfiles",
"verifyemail", "verifyemail",
"Viewmode", "Viewmode",
"viewonly", "viewonly",
"WAKEDEVICE",
"wakedevices", "wakedevices",
"Walkthru", "Walkthru",
"wanonly", "wanonly",
"Webauthn",
"webcerthash",
"webdefault",
"webemailspath", "webemailspath",
"webider",
"webpublicpath", "webpublicpath",
"webpush", "webpush",
"webrelay",
"webrelaydata",
"webrelayserver", "webrelayserver",
"webrequest",
"webrtc", "webrtc",
"webrtconfig", "webrtconfig",
"webserver", "webserver",
"websockets", "websockets",
"WEBSSL", "WEBSSL",
"webstate",
"webviewspath", "webviewspath",
"WELCOMEMSG",
"welcomepicture", "welcomepicture",
"welcomepicturefullscreen",
"welcometext", "welcometext",
"wgetoptionshttp",
"wgetoptionshttps",
"wildleek",
"winassistant",
"winpath",
"winrouter",
"winservice", "winservice",
"wsagents",
"wscompression", "wscompression",
"wsrelays",
"wssessioncount", "wssessioncount",
"wssessions", "wssessions",
"xarg",
"xbytes",
"xcmd",
"xdomain",
"xdomains", "xdomains",
"xenv", "xenv",
"xevents",
"xfile",
"xfilelen",
"xfilepath",
"xflags",
"xforwardedhost",
"xinstall", "xinstall",
"xjslint", "xjslint",
"xmeshes", "xmeshes",
"xpad", "xpad",
"xpassword",
"xrelay",
"xrestart", "xrestart",
"xstate",
"xtls",
"xtransport",
"xuninstall", "xuninstall",
"xuserid",
"xusername",
"xxdata",
"xxprocess", "xxprocess",
"xxurl", "xxurl",
"xxuser",
"xxxprocess", "xxxprocess",
"Ylian", "Ylian",
"yubikey", "yubikey"
"yubikeyotp",
"zdata",
"zipfile"
] ]
} }

View file

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2017-2025 Intel Corporation Copyright 2017-2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View file

@ -113,7 +113,6 @@
<Compile Include="meshdesktopmultiplex.js" /> <Compile Include="meshdesktopmultiplex.js" />
<Compile Include="meshipkvm.js" /> <Compile Include="meshipkvm.js" />
<Compile Include="meshmail.js" /> <Compile Include="meshmail.js" />
<Compile Include="meshmessaging.js" />
<Compile Include="meshrelay.js" /> <Compile Include="meshrelay.js" />
<Compile Include="meshsms.js" /> <Compile Include="meshsms.js" />
<Compile Include="meshscanner.js" /> <Compile Include="meshscanner.js" />
@ -241,6 +240,7 @@
<Compile Include="redirserver.js" /> <Compile Include="redirserver.js" />
<Compile Include="taskmanager.js" /> <Compile Include="taskmanager.js" />
<Compile Include="translate\translate.js" /> <Compile Include="translate\translate.js" />
<Compile Include="ua-parser.js" />
<Compile Include="webauthn.js" /> <Compile Include="webauthn.js" />
<Compile Include="webrelayserver.js" /> <Compile Include="webrelayserver.js" />
<Compile Include="webserver.js" /> <Compile Include="webserver.js" />
@ -440,6 +440,7 @@
<Content Include="LICENSE" /> <Content Include="LICENSE" />
<Content Include="meshcentral-config-schema.json" /> <Content Include="meshcentral-config-schema.json" />
<Content Include="package.json" /> <Content Include="package.json" />
<Content Include="plugin_development.md" />
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.application" /> <Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.application" />
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.config.deploy" /> <Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.config.deploy" />
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.deploy" /> <Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.deploy" />
@ -594,14 +595,12 @@
<Content Include="readme.md" /> <Content Include="readme.md" />
<Content Include="sample-config-advanced.json" /> <Content Include="sample-config-advanced.json" />
<Content Include="sample-config.json" /> <Content Include="sample-config.json" />
<Content Include="SECURITY.md" />
<Content Include="SourceFileList.txt" /> <Content Include="SourceFileList.txt" />
<Content Include="translate\readme.txt" /> <Content Include="translate\readme.txt" />
<Content Include="translate\translate.json" /> <Content Include="translate\translate.json" />
<Content Include="views\agentinvite.handlebars" /> <Content Include="views\agentinvite.handlebars" />
<Content Include="views\default-mobile.handlebars" /> <Content Include="views\default-mobile.handlebars" />
<Content Include="views\default.handlebars" /> <Content Include="views\default.handlebars" />
<Content Include="views\default3.handlebars" />
<Content Include="views\download.handlebars" /> <Content Include="views\download.handlebars" />
<Content Include="views\download2.handlebars" /> <Content Include="views\download2.handlebars" />
<Content Include="views\error404-mobile.handlebars" /> <Content Include="views\error404-mobile.handlebars" />
@ -681,8 +680,6 @@
<Folder Include="typings\globals\ajv\" /> <Folder Include="typings\globals\ajv\" />
<Folder Include="typings\globals\async\" /> <Folder Include="typings\globals\async\" />
<Folder Include="typings\globals\axios\" /> <Folder Include="typings\globals\axios\" />
<Folder Include="typings\globals\big-integer\" />
<Folder Include="typings\globals\busboy\" />
<Folder Include="typings\globals\connect-redis\" /> <Folder Include="typings\globals\connect-redis\" />
<Folder Include="typings\globals\cookie-session\" /> <Folder Include="typings\globals\cookie-session\" />
<Folder Include="typings\globals\core-js\" /> <Folder Include="typings\globals\core-js\" />
@ -696,7 +693,6 @@
<Folder Include="typings\globals\he\" /> <Folder Include="typings\globals\he\" />
<Folder Include="typings\globals\hooker\" /> <Folder Include="typings\globals\hooker\" />
<Folder Include="typings\globals\http-errors\" /> <Folder Include="typings\globals\http-errors\" />
<Folder Include="typings\globals\ip\" />
<Folder Include="typings\globals\is-plain-object\" /> <Folder Include="typings\globals\is-plain-object\" />
<Folder Include="typings\globals\jsbn\" /> <Folder Include="typings\globals\jsbn\" />
<Folder Include="typings\globals\klaw\" /> <Folder Include="typings\globals\klaw\" />
@ -713,12 +709,10 @@
<Folder Include="typings\globals\once\" /> <Folder Include="typings\globals\once\" />
<Folder Include="typings\globals\passport\" /> <Folder Include="typings\globals\passport\" />
<Folder Include="typings\globals\pg-pool\" /> <Folder Include="typings\globals\pg-pool\" />
<Folder Include="typings\globals\rx-lite\" />
<Folder Include="typings\globals\split2\" /> <Folder Include="typings\globals\split2\" />
<Folder Include="typings\globals\sprintf-js\" /> <Folder Include="typings\globals\sprintf-js\" />
<Folder Include="typings\globals\sqlite3\" /> <Folder Include="typings\globals\sqlite3\" />
<Folder Include="typings\globals\type-check\" /> <Folder Include="typings\globals\type-check\" />
<Folder Include="typings\globals\ua-parser-js\" />
<Folder Include="typings\globals\underscore\" /> <Folder Include="typings\globals\underscore\" />
<Folder Include="typings\globals\uuid\" /> <Folder Include="typings\globals\uuid\" />
<Folder Include="typings\globals\window-size\" /> <Folder Include="typings\globals\window-size\" />
@ -728,8 +722,6 @@
<TypeScriptCompile Include="typings\globals\ajv\index.d.ts" /> <TypeScriptCompile Include="typings\globals\ajv\index.d.ts" />
<TypeScriptCompile Include="typings\globals\async\index.d.ts" /> <TypeScriptCompile Include="typings\globals\async\index.d.ts" />
<TypeScriptCompile Include="typings\globals\axios\index.d.ts" /> <TypeScriptCompile Include="typings\globals\axios\index.d.ts" />
<TypeScriptCompile Include="typings\globals\big-integer\index.d.ts" />
<TypeScriptCompile Include="typings\globals\busboy\index.d.ts" />
<TypeScriptCompile Include="typings\globals\connect-redis\index.d.ts" /> <TypeScriptCompile Include="typings\globals\connect-redis\index.d.ts" />
<TypeScriptCompile Include="typings\globals\cookie-session\index.d.ts" /> <TypeScriptCompile Include="typings\globals\cookie-session\index.d.ts" />
<TypeScriptCompile Include="typings\globals\core-js\index.d.ts" /> <TypeScriptCompile Include="typings\globals\core-js\index.d.ts" />
@ -743,7 +735,6 @@
<TypeScriptCompile Include="typings\globals\he\index.d.ts" /> <TypeScriptCompile Include="typings\globals\he\index.d.ts" />
<TypeScriptCompile Include="typings\globals\hooker\index.d.ts" /> <TypeScriptCompile Include="typings\globals\hooker\index.d.ts" />
<TypeScriptCompile Include="typings\globals\http-errors\index.d.ts" /> <TypeScriptCompile Include="typings\globals\http-errors\index.d.ts" />
<TypeScriptCompile Include="typings\globals\ip\index.d.ts" />
<TypeScriptCompile Include="typings\globals\is-plain-object\index.d.ts" /> <TypeScriptCompile Include="typings\globals\is-plain-object\index.d.ts" />
<TypeScriptCompile Include="typings\globals\jsbn\index.d.ts" /> <TypeScriptCompile Include="typings\globals\jsbn\index.d.ts" />
<TypeScriptCompile Include="typings\globals\klaw\index.d.ts" /> <TypeScriptCompile Include="typings\globals\klaw\index.d.ts" />
@ -760,12 +751,10 @@
<TypeScriptCompile Include="typings\globals\once\index.d.ts" /> <TypeScriptCompile Include="typings\globals\once\index.d.ts" />
<TypeScriptCompile Include="typings\globals\passport\index.d.ts" /> <TypeScriptCompile Include="typings\globals\passport\index.d.ts" />
<TypeScriptCompile Include="typings\globals\pg-pool\index.d.ts" /> <TypeScriptCompile Include="typings\globals\pg-pool\index.d.ts" />
<TypeScriptCompile Include="typings\globals\rx-lite\index.d.ts" />
<TypeScriptCompile Include="typings\globals\split2\index.d.ts" /> <TypeScriptCompile Include="typings\globals\split2\index.d.ts" />
<TypeScriptCompile Include="typings\globals\sprintf-js\index.d.ts" /> <TypeScriptCompile Include="typings\globals\sprintf-js\index.d.ts" />
<TypeScriptCompile Include="typings\globals\sqlite3\index.d.ts" /> <TypeScriptCompile Include="typings\globals\sqlite3\index.d.ts" />
<TypeScriptCompile Include="typings\globals\type-check\index.d.ts" /> <TypeScriptCompile Include="typings\globals\type-check\index.d.ts" />
<TypeScriptCompile Include="typings\globals\ua-parser-js\index.d.ts" />
<TypeScriptCompile Include="typings\globals\underscore\index.d.ts" /> <TypeScriptCompile Include="typings\globals\underscore\index.d.ts" />
<TypeScriptCompile Include="typings\globals\uuid\index.d.ts" /> <TypeScriptCompile Include="typings\globals\uuid\index.d.ts" />
<TypeScriptCompile Include="typings\globals\window-size\index.d.ts" /> <TypeScriptCompile Include="typings\globals\window-size\index.d.ts" />

View file

@ -1,49 +0,0 @@
# Security Policy
## Supported Versions
Any version of MeshCentral 1.x.x is supported.
| Version | Supported |
| ------- | ------------------ |
| 1.x.x | :white_check_mark: |
| < 1.0 | :x: |
## Reporting a Vulnerability
Please report any concerns or security issue to Ylian Saint-Hilaire (ylianst@gmail.com). If needed, use my PGP key below.
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG v1.56
mQMuBF2gC4sRCAClFNvMCCVW3ego3UHBQ6LhSenJfaZYhvn8gaGuemSQxqTI6bla
BTAv3aMtQnvqlSuadMMegb+FO6hnaQMlGvpVA1qpkSzgrPS5HrBD3H33J2Nj3i93
ZpDPpxdI0ehCj6IJPnl0GxGbpKIN8YpJUFl44wv1lMRFI1lgyb+dCoO60irYdNQB
PV85BI+DwPfOBFHunwR78nqMvpvsk9HaeHjEP7oXr952/7EazUowZsMlEfkYnw5S
+tLfpCoY3QWkektpJP40nMJSKQdV2NEuED99doA0X+7P1vsvFFFyMH69dnU2uSay
XCHpkAbntBy0BGmtF1RnTcOMv2V/LPXnlMdvAQCbmLQzNra3r163tcdRY0jSs+pZ
1L3w5tHNj2dzhfpa7wf/SIuds6QTr2LCN6miLoSVCRMMpT7d771b16GwQqWEXzN2
+h7dYqrssHPOa8FSUrPerz0+0eFcbMSm5/L/4KXWXoQthURv8aMP9E0iVoUYaaKB
7U+5vFEZbpoOZyZmTAjXQMSNZCft0azA82Q+G85euyicWtMv48yNVzUhkdh+M2ud
ohkXX2Aor1TqpBJoIeWke7j9D+Bo+lu61zPRx5ed9teUeLJCwqNEjlE+6gre5kxF
PoreAtn59QYcBIpzQEWVMbNFlDAR4jMyqIoKCGfBPiRw2V+kunbzqiGQEglIFfOt
6sTN/+CJh0ei976VDmE0Z1kMN+CNLgIjIw8fl02V9QgAnHcpqtVUxR4dbGOhVDq5
lWv+K75QQlWyXC2k+KboXcaCvH0WZEBACYzO0CfrZ5hP9BSkbj5usSUVGGHwEFAJ
t+/04KVY71fW281Ej5kGNaIKxeKsx6+hMo+UXb5ZM+6fANNNxs1cK95sTH6PjkyB
tsKxLoa3CV2v9mSE5JiKKt74R9nXVo7PXf6DizwAU2l30Lb6y6y0OdXdCCPAG8Ij
FrMgPu5MtjgsO5DnkZfUqDPWHhOgEPyOh3Ho+pvDhNYh5cm2eLQ8g5orzs2FHwbZ
DpAHwCdqrlcpBlKJ4W/MZdf1fg2PjqaTWm7ZFiGr91P0F6kltTLWbVKTjLdS0T+D
L7QnWWxpYW4gU2FpbnQtSGlsYWlyZSA8eWxpYW5zdEBnbWFpbC5jb20+iF4EExEI
AAYFAl2gC4sACgkQg7j/r4DH+kD/3gD+MRedlM53VzOtNOpS6mqDAxj1aWP90HN0
AqO6zuCTyGgBAJlunLFKH8IUetmQOhiohB8HVhdm/q4lKRDV7sHdplDyuMwEXaAL
ixACAJSU/sCV87he4oZUKzg2/IGl3QoDSbTCOd04dE1IjPjjHbi8t9M7Qau55aM8
ypFEsc7zMslL8Fc78EejrKmM3zsB/RU9XWFyrbQwRbaK6OHeEHC2E3AFaG0p09c6
d0kZloHuWyEsm5a/3PpbIM1eP9IESJXWCc+bQQt6DxLKHLmkKMwB/icWMg8uMJlx
aady8TEq7LH5oFVKsglnwuN1nIkecrf77TVkEqTjIxS6TiOup6zOnioFNKLYBAH0
WUnJEYFvx4OIXgQYEQgABgUCXaALiwAKCRCDuP+vgMf6QGFTAQCUj2gGwsFlN0eR
Wowv4eLcc3FwQ+lBElUctKg8vNFb0gD/ZWVWsWwKerNgNnf7RGD9mt8G2CKvdgGG
oZ2hPP2gU9w=
=roW4
-----END PGP PUBLIC KEY BLOCK-----
```

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -37,7 +37,7 @@
"meshName": "Skupinové jméno", "meshName": "Skupinové jméno",
"meshId": "Identifikátor skupiny", "meshId": "Identifikátor skupiny",
"serverId": "Identifikátor serveru", "serverId": "Identifikátor serveru",
"setup": "Nastavit", "setup": "Založit",
"update": "Aktualizace", "update": "Aktualizace",
"install": "Instalace", "install": "Instalace",
"uninstall": "Odinstalace", "uninstall": "Odinstalace",
@ -52,7 +52,7 @@
"zenity": "Zkuste nainstalovat / aktualizovat Zenity a spustit znovu", "zenity": "Zkuste nainstalovat / aktualizovat Zenity a spustit znovu",
"status": [ "status": [
"NENÍ INSTALOVÁN", "NENÍ INSTALOVÁN",
"SPUŠTĚNO", "BĚH",
"NEFUNGUJE" "NEFUNGUJE"
], ],
"statusDescription": "Aktuální stav agenta", "statusDescription": "Aktuální stav agenta",
@ -620,129 +620,5 @@
"elevation": "Permissões Elevadas são necessárias para instalar/desinstalar este software", "elevation": "Permissões Elevadas são necessárias para instalar/desinstalar este software",
"graphicalerror": "A versão gráfica do instalador não pode ser executada neste sistema", "graphicalerror": "A versão gráfica do instalador não pode ser executada neste sistema",
"description": "Clique nos botões abaixo para instalar ou desinstalar este software de gerenciamento remoto. Quando instalado, este software é executado em segundo plano permitindo que este computador seja gerenciado e controlado por um administrador remoto" "description": "Clique nos botões abaixo para instalar ou desinstalar este software de gerenciamento remoto. Quando instalado, este software é executado em segundo plano permitindo que este computador seja gerenciado e controlado por um administrador remoto"
},
"bs": {
"agent": "Agent",
"agentVersion": "Nova verzija",
"group": "Grupa uređaja",
"url": "URL servera",
"meshName": "Ime grupe",
"meshId": "Grupni identifikator",
"serverId": "Identifikator servera",
"setup": "Postaviti",
"update": "Ažuriraj",
"install": "Instaliraj",
"uninstall": "Deinstalirati",
"connect": "Povežite se",
"disconnect": "Prekini vezu",
"cancel": "Otkaži",
"close": "Zatvori",
"pressok": "Pritisnite OK da prekinete vezu",
"elevation": "Za instaliranje/deinstaliranje ovog softvera potrebne su povišene dozvole.",
"sudo": "Molimo pokušajte ponovo sa sudo.",
"ctrlc": "Pritisnite Ctrl-C za izlaz.",
"commands": "Možete pokrenuti tekstualnu verziju iz komandne linije sa sljedećim naredbama",
"graphicalerror": "Grafička verzija ovog instalatera ne može da radi na ovom sistemu",
"zenity": "Pokušajte instalirati/ažurirati Zenity i pokrenite ponovo",
"status": [
"NIJE INSTALIRANO",
"RUNNING",
"NOT RUNNING"
],
"statusDescription": "Trenutni status agenta",
"description": "Kliknite na dugmad ispod da instalirate ili deinstalirate ovaj softver za daljinsko upravljanje. Kada je instaliran, ovaj softver radi u pozadini, što omogućava da ovim računarom upravlja i kontroliše udaljeni administrator."
},
"hu": {
"agent": "Agent",
"agentVersion": "Új verzió",
"group": "Eszköz csoport",
"url": "Kiszolgáló URL",
"meshName": "Csoport név",
"meshId": "Csoport azonosító",
"serverId": "Kiszolgáló azonosító",
"setup": "Beállítás",
"update": "Frissítés",
"install": "Telepítés",
"uninstall": "Eltávolítás",
"connect": "Kapcsolódás",
"disconnect": "Lekapcsolódás",
"cancel": "Mégse",
"close": "Bezár",
"pressok": "Press OK to disconnect",
"elevation": "A szoftver telepítéséhez/eltávolításához megnövelt jogosultságok szükségesek.",
"sudo": "Kérjük, próbálja meg újra a sudo használatával.",
"ctrlc": "A kilépéshez nyomja meg a Ctrl-C billentyűt.",
"commands": "A szöveges változatot a parancssorból futtathatja a következő parancs(okk)al",
"graphicalerror": "A telepítő grafikus verziója nem futtatható ezen a rendszeren.",
"zenity": "Próbálja meg telepíteni/frissíteni a Zenity-t, és indítsa újra",
"status": [
"NINCS TELEPÍTVE",
"FUT",
"NEM FUT"
],
"statusDescription": "Jelenlegi agent állapota",
"description": "Kattintson a Telepítés vagy Eltávolítás gombokra a Távfelügyeleti alkalmazás telepítéséhez vagy eltávolításához. Telepítés után ez az alkalmazás a háttérben fut, lehetővé téve, hogy a számítógépet egy távoli rendszergazda kezelje."
},
"ca": {
"agent": "Agent",
"agentVersion": "Nova versió",
"group": "Grup de dispositius",
"url": "URL del servidor",
"meshName": "Nom del grup",
"meshId": "Identificador de grup",
"serverId": "Identificador del servidor",
"setup": "Configuració",
"update": "Actualització",
"install": "Instal·lar",
"uninstall": "Desinstal·la",
"connect": "Connecta't",
"disconnect": "Desconnecta",
"cancel": "Cancel · lar",
"close": "Tanca",
"pressok": "Premeu D'acord per desconnectar",
"elevation": "Es necessiten permisos elevats per instal·lar/desinstal·lar aquest programari.",
"sudo": "Si us plau, torna-ho a provar amb sudo.",
"ctrlc": "Premeu Ctrl-C per sortir.",
"commands": "Podeu executar la versió de text des de la línia d'ordres amb les següents ordres",
"graphicalerror": "La versió gràfica d'aquest instal·lador no pot executar-se en aquest sistema",
"zenity": "Proveu d'instal·lar/actualitzar Zenity i torneu a executar-lo",
"status": [
"NO ESTÀ INSTAL · LAT",
"CÓRRER",
"NO CORRE"
],
"statusDescription": "Estat actual de l'agent",
"description": "Feu clic als botons següents per instal·lar o desinstal·lar aquest programari de gestió remota. Quan s'instal·la, aquest programari s'executa en segon pla i permet que aquest ordinador sigui gestionat i controlat per un administrador remot."
},
"uk": {
"agent": "Агент",
"agentVersion": "Нова Версія",
"group": "Група Пристроїв",
"url": "URL Сервера",
"meshName": "Ім'я Групи",
"meshId": "Ідентифікатор групи",
"serverId": "Ідентифікатор серверу",
"setup": "Налаштувати",
"update": "Оновлення",
"install": "Інсталювати",
"uninstall": "Видалити",
"connect": "Підключитися",
"disconnect": "Відключити",
"cancel": "Скасувати",
"close": "Закрити",
"pressok": "Натисніть OK, щоб від'єднатися",
"elevation": "Для інсталяції/деінсталяції цього програмного забезпечення потрібні підвищені дозволи.",
"sudo": "Будь ласка, спробуйте ще раз за допомогою sudo.",
"ctrlc": "Натисніть Ctrl-C, щоб вийти",
"commands": "Ви можете запустити текстову версію з командного рядка за допомогою таких команд",
"graphicalerror": "Графічна версія цього інсталятора не може працювати в цій системі",
"zenity": "Спробуйте встановити/оновити Zenity та запустіть наново",
"status": [
"НЕ ВСТАНОВЛЕНО",
"ВИКОНУЄТЬСЯ",
"НЕ ПРАЦЮЄ"
],
"statusDescription": "Поточний Статус Агента",
"description": "Клікнути кнопки нижче, щоб інсталювати або видалити це програмне забезпечення для віддаленого керування. Після інсталювання ця програма працює у фоновому режимі, що дозволяє віддаленому адміністратору керувати цим комп'ютером."
} }
} }

View file

@ -0,0 +1,11 @@
@ECHO OFF
MD modules_meshcmd_min
MD modules_meshcore_min
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcmd.js
RENAME meshcmd.js.min meshcmd.min.js
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcore.js
RENAME meshcore.js.min meshcore.min.js
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minifydir C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcore C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcore_min
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minifydir C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcmd C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcmd_min

View file

@ -0,0 +1,20 @@
@ECHO OFF
MD modules_meshcmd_min
MD modules_meshcore_min
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" compressalljs "modules_meshcore" "modules_meshcore_min"
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" compressalljs "modules_meshcmd" "modules_meshcmd_min"
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" meshcore.js
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" meshcmd.js
REM del meshcore.min.js
REM %LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcore.js
REM rename meshcore.js.min meshcore.min.js
REM del meshcmd.min.js
REM %LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcmd.js
REM rename meshcmd.js.min meshcmd.min.js
REM Minify the translations
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify modules_meshcore\coretranslations.json
COPY modules_meshcore\coretranslations.json.min modules_meshcore_min\coretranslations.json
DEL modules_meshcore\coretranslations.json.min

View file

@ -1,134 +1,134 @@
{ {
"3": { "3": {
"filename": "MeshService.exe", "filename": "MeshService.exe",
"hash": "33AE44E73CA79EDD443661F8D6205DF59DE7D03B0AC730A37D283C9CE4079E6136FFC30BC1B79DA8FB05F03CBDE75D06", "hash": "C0E5DB22DE5DED510C48141D7CFE4807F98B8205D680F5FC8A5D15950F17A1465E0953B7BFA7FAEED72019E765E1C8E1",
"size": 3793408, "size": 3680256,
"mtime": "2022-08-25T17:55:54Z" "mtime": "1985-10-26T08:15:00Z"
}, },
"4": { "4": {
"filename": "MeshService64.exe", "filename": "MeshService64.exe",
"hash": "C809BAB1F0B988F1436E1033D9F07A782412A6CC7ECCF4AC52CCCBD91D7B56D401F2AB5FABC71A66F91B20E6FCA393D4", "hash": "47A927806EDB6DFAC2C79467719FADA0F3625010D551C6D0EA6EA7DB99F088C088E70F562416FC1809B014913CFEA7E0",
"size": 3422720, "size": 3293184,
"mtime": "2022-08-25T17:55:24Z" "mtime": "1985-10-26T08:15:00Z"
}, },
"5": { "5": {
"filename": "meshagent_x86", "filename": "meshagent_x86",
"hash": "024A8FCE66C277CFAA375B6F5A12E18D08BF2F8EE494C4408544D93F219F7208BACF056F79A2340428C3C34F765E325E", "hash": "E984791A6FB96E06191AEA1D7B3066AB8B2170DC7B8A64D7C9A605CDC79B463541D994587E85E3FD4644359329344734",
"size": 3666464, "size": 3650016,
"mtime": "2022-08-29T17:48:58Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"6": { "6": {
"filename": "meshagent_x86-64", "filename": "meshagent_x86-64",
"hash": "DC5924847AD22C058D1009BE7EDFAFEAF248DEC706C263736B254BA5917D274A21BAE0D025852EC788007EF3688CDC64", "hash": "F6A48178D7BCE798CDF36AC8F49D9650674E38E266DB396A84657EE8FD81BF85FA998456245F2AFE4A20FDD08CD73D2E",
"size": 3741136, "size": 3724624,
"mtime": "2022-08-29T17:49:06Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"7": { "7": {
"filename": "meshagent_mips", "filename": "meshagent_mips",
"hash": "C49212CA4BF2D1F031F376C0157A4B9C5EA5ACD08180662F27F2EA54F990C2A7840B5A3BF7F66D85EE194EF675008D09", "hash": "2D913C118114219CF127D9415174645A3F11464A4B13D07A702AFC2A836381C52C4A2854403215DAFF4582C058E8B824",
"size": 4547696, "size": 4522304,
"mtime": "2022-08-29T17:49:13Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"9": { "9": {
"filename": "meshagent_arm", "filename": "meshagent_arm",
"hash": "5217EBF6638EDC64FFFBE3B53BF9DC640D630CC69B9CE484C1CA274530C248D248AC4F4E84071A34CD504039D8D0B022", "hash": "AD1C9D2A1E468AEB26FD6443581C3CE3F5F8D0A3779BA0EA5BA06C20B5094B095B5F0D0F104B2F26053877E5D005FBAB",
"size": 3148064, "size": 3132180,
"mtime": "2022-08-29T17:49:22Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"13": { "13": {
"filename": "meshagent_pogo", "filename": "meshagent_pogo",
"hash": "1523191069F30678C607E32F557CD5F9125A963C671CE7A7F6FB8ADD9B9BFB890AC1A6248872EAE899737F378F54FFF2", "hash": "F9E19D72922732BC4C9F84F90CAB380E6A3851B8137A69AB648E1B145BA4F257B5C2C47BBE36CBE62E364328854DD844",
"size": 3156744, "size": 3140884,
"mtime": "2022-08-29T17:49:32Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"15": { "15": {
"filename": "meshagent_poky", "filename": "meshagent_poky",
"hash": "36090B49C98D7A3E7515EC2D22E5C47A4FD9BA35B517949BAF04B39A7CE91378656A7F3FC132C5E43FD1D087B3C9226E", "hash": "DFBF910AC01FE7D8BD2E6649908E0BBE0C553C12ACADB4C73C32BC65BCDCCDF336C39BA47A08C6659F9CB8E475C3677F",
"size": 3796600, "size": 3776024,
"mtime": "2022-08-29T17:49:42Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"16": { "16": {
"filename": "meshagent_osx-x86-64", "filename": "meshagent_osx-x86-64",
"hash": "F7A3EBEC3D855EBFB2C72271C17196C7692EB2685DCBA70B56B63C80D6CF0DAA7DF00657BB4A12F4C0D92281B1BB47FE", "hash": "77A87BCAE3534061CE15060C4F8971074B7AEBC88957CC9FF50BF8F6B234E3AFAE48DCB9A44681A24393F20191BB3DA1",
"size": 4670736, "size": 4391904,
"mtime": "2022-08-23T03:31:00Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"18": { "18": {
"filename": "meshagent_poky64", "filename": "meshagent_poky64",
"hash": "FD61B913D2239621FDCC2E949BF16FCAE3F9D46D25EEF74DA0A7971F30A44E315A4231AF824241940391A3F112794A27", "hash": "0DDF6A2CABC3B1D40CBE9CA4A6EB2103308F228D5332F64E3C9B01A54BC968B0120D2A50B71111D70682435A07577ABD",
"size": 3495416, "size": 3478872,
"mtime": "2022-08-29T17:49:52Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"19": { "19": {
"filename": "meshagent_x86_nokvm", "filename": "meshagent_x86_nokvm",
"hash": "BF125A52656DFE6665E78AB22ED652F4C65C17624A12BCAC2F0691A255AF208C3E883101266F3E80052F4CFE8602B29B", "hash": "2AFC43684BD2A2601FAA32BF86F35EAEB29CDD00ABE3BEB3446448EC44E3151E459909569044681C507FE11A82139914",
"size": 3385732, "size": 3365188,
"mtime": "2022-08-29T17:50:00Z" "mtime": "2022-08-17T21:09:42Z"
}, },
"20": { "20": {
"filename": "meshagent_x86-64_nokvm", "filename": "meshagent_x86-64_nokvm",
"hash": "9AB50A5419A2BAFC8DC485C3F24387622689FE3A0C146317CE3EA951F3EE2E4902CCE3878F2098C6EB23A848E510E478", "hash": "1B198D624FA99E4D6B52AD139A19259B491FA233A2783F5E4C46955A6AD37DDF5053D7F022C95C8F04684CCADFD2CC3D",
"size": 3446192, "size": 3425584,
"mtime": "2022-08-29T17:50:08Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"24": { "24": {
"filename": "meshagent_arm-linaro", "filename": "meshagent_arm-linaro",
"hash": "DCC5B487A200F9670B33BE603F52088856FB249CC03F5B62D1617CA9A95B55329B120FE4D3FFD72B2E5FE1ADE302CF81", "hash": "2F5D211E983A738ABE31A6EAF4B73629FD937D34D5BD8380A420BAB7108040CA2320EADA8F02CFEF763A3C1D0EA8F1A2",
"size": 2211156, "size": 2194704,
"mtime": "2022-08-29T17:50:21Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"25": { "25": {
"filename": "meshagent_armhf", "filename": "meshagent_armhf",
"hash": "1EDCE4E132927B432F60A3D262368B3DF54B012EDD786EAD31139646B5D9168297C32D13C7D822CE5FEF7FE44B65B4A0", "hash": "37F717A44CDA07F88D51A5FF9FD220FEA7F61307BD3A418CC8D9E45D9B9EDB1CB069A9398318E0DF2042C4D204657F7D",
"size": 3181452, "size": 3166784,
"mtime": "2022-08-23T03:14:16Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"27": { "27": {
"filename": "meshagent_armhf2", "filename": "meshagent_armhf2",
"hash": "0AE840520D3B677B9767EA097F3AA5A1E24212529E688200F43935DB1541AB9FB441EC2C7BA8002D45299B04695FD037", "hash": "0AE840520D3B677B9767EA097F3AA5A1E24212529E688200F43935DB1541AB9FB441EC2C7BA8002D45299B04695FD037",
"size": 2837724, "size": 2837724,
"mtime": "1985-10-26T08:15:00Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"28": { "28": {
"filename": "meshagent_mips24kc", "filename": "meshagent_mips24kc",
"hash": "88A79B78497D1D004E44D02989A3BE3710D3BEE0A129F98579FFAA826FAC6C90CD69B9B218B90377438942BA85DAC81C", "hash": "636B02BD3DD7DED0BB79FAF1B991F7DB89FF23DC1373D3F5E3EA76897B4BF44E8F00A57A3B6C87EBECA8142D9AD5B7B9",
"size": 4181416, "size": 4163768,
"mtime": "2022-08-23T03:15:24Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"29": { "29": {
"filename": "meshagent_osx-arm-64", "filename": "meshagent_osx-arm-64",
"hash": "CFE022146F2ED61E68F907E57E3704CC7F409D7F2B4D87E64ED6D83C53F41777BCDDCCF42DF8B8BB25CCEC9A93D799C7", "hash": "D1D8CDAF59105E4E8A753CCC9032F1653AE4DB973765E3E009CA9F352BA7B3C8E487B4F34BB9A0C4A629C29DE55FFF69",
"size": 3945576, "size": 3911880,
"mtime": "2022-08-23T03:31:00Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"30": { "30": {
"filename": "meshagent_freebsd_x86-64", "filename": "meshagent_freebsd_x86-64",
"hash": "5C2CDDA2E7AB5068D990FBC725D8D5E3EA2724A0E001C226C0C7BB9F3A46492880BF260B5DD9E733F87EB68BA7494BD6", "hash": "4EA888AAD34D104E7FD898E4F331A9A65EB2EB85C7181DADF1E2A5C04B8F22B91B46AEBDC512D714D11D04B4C2B1EA3E",
"size": 4673560, "size": 4657032,
"mtime": "2022-08-23T03:31:12Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"32": { "32": {
"filename": "meshagent_aarch64", "filename": "meshagent_aarch64",
"hash": "21C97445FA93C2A42337AD0E336F840A05EC553F8C040F6021C16339567F8A063EB06876D62C2C2924BD9F656434E9DB", "hash": "27B50D0696EA3156BA91CBE0EFC2775217A2DCB1BC7AB0B079DCDE52E7D2B3E2A2647FDC6F74087C4D8D748FD90F59AD",
"size": 3248496, "size": 3227888,
"mtime": "2022-08-23T03:13:02Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"40": { "40": {
"filename": "meshagent_mipsel24kc", "filename": "meshagent_mipsel24kc",
"hash": "A58CF777ACA3E9B3F7C0FC664E5EAC1F95C3FD03ABDE93E2B06547D0BA1C671A9E67F252CACD9BCBD2019561E18ED7DF", "hash": "31F3377C4703CFFDD6905FC0EFC96C4BB328474CE62BECB2E79860C5841CA9019EFC6945974847D03797EE49529DDDE0",
"size": 4177288, "size": 4160072,
"mtime": "2022-08-23T03:16:32Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"41": { "41": {
"filename": "meshagent_aarch64-cortex-a53", "filename": "meshagent_aarch64-cortex-a53",
"hash": "CC84858AD16C644096B87E3686B318F82CD1A39015FF17D93456456F0A51D4A2D4DEC7F6EAA2ABB065D7EAD28CD024A2", "hash": "E6D65EB2F8013E4DB811E2E73150C063EB41DF8C9D8321D1F2CA2FAEEA7DBA203032AD4E95A467A0D8FD836E18EE3D0D",
"size": 3076424, "size": 3059896,
"mtime": "2022-08-23T03:17:42Z" "mtime": "2022-08-17T21:09:41Z"
}, },
"10005": { "10005": {
"filename": "meshagent_osx-universal-64", "filename": "meshagent_osx-universal-64",
"hash": "D320CA61D59FD8D76CF681CFE78A94CE37C47DBCAA8B29DF483F42C000EA9B655B5E5909A2AD6699D45D2D7691FF4964", "hash": "5AB5C0580E9B7B0689C20FD01561997D7B17CA5E14C747E981888C74B8CCECEE827E141ECF6CBD76C5040051C09DE840",
"size": 8647784, "size": 8335560,
"mtime": "2022-08-23T03:31:00Z" "mtime": "2022-08-17T21:09:41Z"
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -588,7 +588,7 @@ function run(argv) {
} }
amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } }); amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } });
amtMei.getProvisioningMode(function (result) { if (result) { mestate.ProvisioningMode = result; } }); amtMei.getProvisioningMode(function (result) { if (result) { mestate.ProvisioningMode = result; } });
amtMei.getEHBCState(function (result) { if (result) { mestate.ehbc = ((result === true) || (typeof result == 'object') && (result.EHBC === true)); } }); amtMei.getEHBCState(function (result) { mestate.ehbc = ((result === true) || (typeof result == 'object') && (result.EHBC === true)); });
amtMei.getControlMode(function (result) { if (result) { mestate.controlmode = result; } }); amtMei.getControlMode(function (result) { if (result) { mestate.controlmode = result; } });
amtMei.getMACAddresses(function (result) { if (result) { mestate.mac = result; } }); amtMei.getMACAddresses(function (result) { if (result) { mestate.mac = result; } });
amtMei.getLanInterfaceSettings(0, function (result) { if (result) { mestate.net0 = result; } }); amtMei.getLanInterfaceSettings(0, function (result) { if (result) { mestate.net0 = result; } });

File diff suppressed because it is too large Load diff

View file

@ -103,13 +103,14 @@ if (msh.agentName) { connectArgs.push('--agentName="' + msh.agentName + '"'); }
function _install(parms) function _install(parms)
{ {
var i;
var mstr = require('fs').createWriteStream(process.execPath + '.msh', { flags: 'wb' }); var mstr = require('fs').createWriteStream(process.execPath + '.msh', { flags: 'wb' });
mstr.write('MeshName=' + msh.MeshName + '\n');
for (i in msh) mstr.write('MeshType=' + msh.MeshType + '\n');
{ mstr.write('MeshID=' + msh.MeshID + '\n');
mstr.write(i + '=' + msh[i] + '\n'); mstr.write('ServerID=' + msh.ServerID + '\n');
} mstr.write('MeshServer=' + msh.MeshServer + '\n');
if (msh.agentName) { mstr.write('agentName=' + msh.agentName + '\n'); }
if (msh.meshServiceName) { mstr.write('meshServiceName=' + msh.meshServiceName + '\n'); }
mstr.end(); mstr.end();
if (parms == null) { parms = []; } if (parms == null) { parms = []; }
@ -155,7 +156,7 @@ if (process.argv.includes('-translations'))
console.log(JSON.stringify(translation)); console.log(JSON.stringify(translation));
process.exit(); process.exit();
} }
if (process.argv.includes('-help') || (process.platform == 'linux' && process.env['XAUTHORITY'] == null && process.env['DISPLAY'] == null && process.argv.length == 1)) if (process.argv.includes('-help'))
{ {
console.log("\n" + translation[lang].commands + ": "); console.log("\n" + translation[lang].commands + ": ");
if ((msh.InstallFlags & 1) == 1) if ((msh.InstallFlags & 1) == 1)
@ -220,7 +221,9 @@ if ((!skip) && ((msh.InstallFlags & 2) == 2))
} }
} }
if (!skip) if (!skip)
{
if (process.platform != 'darwin')
{ {
if (process.argv.includes('-install') || process.argv.includes('-update')) if (process.argv.includes('-install') || process.argv.includes('-update'))
{ {
@ -231,10 +234,6 @@ if ((!skip) && ((msh.InstallFlags & 2) == 2))
{ {
p.push('--installPath="' + process.argv[i].split('=').pop() + '"'); p.push('--installPath="' + process.argv[i].split('=').pop() + '"');
} }
else if(process.argv[i].startsWith('--'))
{
p.push(process.argv[i]);
}
} }
_install(p); _install(p);
process.exit(); process.exit();
@ -272,11 +271,12 @@ if ((!skip) && ((msh.InstallFlags & 2) == 2))
process.exit(); process.exit();
} }
} }
if (process.platform == 'darwin')
{
if (!require('user-sessions').isRoot()) { console.log('\n' + translation[lang].elevation); process.exit(); }
}
} }
else
{
if (!require('user-sessions').isRoot()) { console.log('\n' + translation[lang].elevation); process.exit(); }
}
}
if (!skip) if (!skip)

View file

@ -98,7 +98,7 @@ module.exports = function CreateAmtRemoteIder() {
// Private method // Private method
obj.ProcessData = function (data) { obj.ProcessData = function (data) {
obj.bytesFromAmt += data.length; obj.bytesFromAmt += data.length;
if (obj.acc == null) { obj.acc = data; } else { obj.acc = Buffer.concat([obj.acc, data]); } if (obj.acc == null) { obj.acc = data; } else { obj.acc = Buffer.concat(obj.acc, data); }
if (obj.debug) console.log('IDER-ProcessData', obj.acc.length, obj.acc.toString('hex')); if (obj.debug) console.log('IDER-ProcessData', obj.acc.length, obj.acc.toString('hex'));
// Process as many commands as possible // Process as many commands as possible

View file

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

View file

@ -225,14 +225,19 @@ function macos_memUtilization()
function windows_thermals() function windows_thermals()
{ {
var ret = []; var ret = [];
try { child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', '/namespace:\\\\root\\wmi', 'PATH', 'MSAcpi_ThermalZoneTemperature', 'get', 'CurrentTemperature']);
ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
if (ret[0]) { child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
for (var i = 0; i < ret.length; ++i) { child.waitExit();
ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2);
} if(child.stdout.str.trim!='')
{
var lines = child.stdout.str.trim().split('\r\n');
for (var i = 1; i < lines.length; ++i)
{
if (lines[i].trim() != '') { ret.push(((parseFloat(lines[i]) / 10) - 273.15).toFixed(2)); }
} }
} catch (ex) { } }
return (ret); return (ret);
} }
@ -280,10 +285,16 @@ function macos_thermals()
return (ret); return (ret);
} }
const platformConfig = { switch(process.platform)
linux: { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals }, {
win32: { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals }, case 'linux':
darwin: { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals } module.exports = { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals };
}; break;
case 'win32':
module.exports = { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals };
break;
case 'darwin':
module.exports = { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals };
break;
}
module.exports = platformConfig[process.platform];

View file

@ -1,902 +0,0 @@
/*
Copyright 2019-2021 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
function trimIdentifiers(val)
{
for(var v in val)
{
if (!val[v] || val[v] == 'None' || val[v] == '') { delete val[v]; }
}
}
function trimResults(val)
{
var i, x;
for (i = 0; i < val.length; ++i)
{
for (x in val[i])
{
if (x.startsWith('_'))
{
delete val[i][x];
}
else
{
if (val[i][x] == null || val[i][x] == 0)
{
delete val[i][x];
}
}
}
}
}
function brief(headers, obj)
{
var i, x;
for (x = 0; x < obj.length; ++x)
{
for (i in obj[x])
{
if (!headers.includes(i))
{
delete obj[x][i];
}
}
}
return (obj);
}
function dataHandler(c)
{
this.str += c.toString();
}
function linux_identifiers()
{
var identifiers = {};
var ret = {};
var values = {};
if (!require('fs').existsSync('/sys/class/dmi/id')) {
if (require('fs').existsSync('/sys/firmware/devicetree/base/model')) {
if (require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim().startsWith('Raspberry')) {
identifiers['board_vendor'] = 'Raspberry Pi';
identifiers['board_name'] = require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim();
identifiers['board_serial'] = require('fs').readFileSync('/sys/firmware/devicetree/base/serial-number').toString().trim();
const memorySlots = [];
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write('vcgencmd get_mem arm && vcgencmd get_mem gpu\nexit\n');
child.waitExit();
try {
const lines = child.stdout.str.trim().split('\n');
if (lines.length == 2) {
memorySlots.push({ Locator: "ARM Memory", Size: lines[0].split('=')[1].trim() })
memorySlots.push({ Locator: "GPU Memory", Size: lines[1].split('=')[1].trim() })
ret.memory = { Memory_Device: memorySlots };
}
} catch (xx) { }
} else {
throw('Unknown board');
}
} else {
throw ('this platform does not have DMI statistics');
}
} else {
var entries = require('fs').readdirSync('/sys/class/dmi/id');
for (var i in entries) {
if (require('fs').statSync('/sys/class/dmi/id/' + entries[i]).isFile()) {
try {
ret[entries[i]] = require('fs').readFileSync('/sys/class/dmi/id/' + entries[i]).toString().trim();
} catch(z) { }
if (ret[entries[i]] == 'None') { delete ret[entries[i]]; }
}
}
entries = null;
identifiers['bios_date'] = ret['bios_date'];
identifiers['bios_vendor'] = ret['bios_vendor'];
identifiers['bios_version'] = ret['bios_version'];
identifiers['bios_serial'] = ret['product_serial'];
identifiers['board_name'] = ret['board_name'];
identifiers['board_serial'] = ret['board_serial'];
identifiers['board_vendor'] = ret['board_vendor'];
identifiers['board_version'] = ret['board_version'];
identifiers['product_uuid'] = ret['product_uuid'];
identifiers['product_name'] = ret['product_name'];
}
try {
identifiers['bios_mode'] = (require('fs').statSync('/sys/firmware/efi').isDirectory() ? 'UEFI': 'Legacy');
} catch (ex) { identifiers['bios_mode'] = 'Legacy'; }
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write('cat /proc/cpuinfo | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n");
child.waitExit();
identifiers['cpu_name'] = child.stdout.str.trim();
if (identifiers['cpu_name'] == "") { // CPU BLANK, check lscpu instead
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write('lscpu | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n");
child.waitExit();
identifiers['cpu_name'] = child.stdout.str.trim();
}
child = null;
// Fetch GPU info
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write("lspci | grep ' VGA ' | tr '\\n' '`' | awk '{ a=split($0,lines" + ',"`"); printf "["; for(i=1;i<a;++i) { split(lines[i],gpu,"r: "); printf "%s\\"%s\\"", (i==1?"":","),gpu[2]; } printf "]"; }\'\nexit\n');
child.waitExit();
try { identifiers['gpu_name'] = JSON.parse(child.stdout.str.trim()); } catch (xx) { }
child = null;
// Fetch Storage Info
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write("lshw -class disk | tr '\\n' '`' | awk '" + '{ len=split($0,lines,"*"); printf "["; for(i=2;i<=len;++i) { model=""; caption=""; size=""; clen=split(lines[i],item,"`"); for(j=2;j<clen;++j) { split(item[j],tokens,":"); split(tokens[1],key," "); if(key[1]=="description") { caption=substr(tokens[2],2); } if(key[1]=="product") { model=substr(tokens[2],2); } if(key[1]=="size") { size=substr(tokens[2],2); } } if(model=="") { model=caption; } if(caption!="" || model!="") { printf "%s{\\"Caption\\":\\"%s\\",\\"Model\\":\\"%s\\",\\"Size\\":\\"%s\\"}",(i==2?"":","),caption,model,size; } } printf "]"; }\'\nexit\n');
child.waitExit();
try { identifiers['storage_devices'] = JSON.parse(child.stdout.str.trim()); } catch (xx) { }
child = null;
// Fetch storage volumes using df
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write('df -T | awk \'NR==1 || $1 ~ ".+"{print $3, $4, $5, $7, $2}\' | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $1, $2, $3, $4, $5}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n');
child.waitExit();
try { ret.volumes = JSON.parse(child.stdout.str.trim()); } catch (xx) { }
child = null;
values.identifiers = identifiers;
values.linux = ret;
trimIdentifiers(values.identifiers);
var dmidecode = require('lib-finder').findBinary('dmidecode');
if (dmidecode != null)
{
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stderr.str = ''; child.stderr.on('data', dataHandler);
child.stdin.write(dmidecode + " -t memory | tr '\\n' '`' | ");
child.stdin.write(" awk '{ ");
child.stdin.write(' printf("[");');
child.stdin.write(' comma="";');
child.stdin.write(' c=split($0, lines, "``");');
child.stdin.write(' for(i=1;i<=c;++i)');
child.stdin.write(' {');
child.stdin.write(' d=split(lines[i], val, "`");');
child.stdin.write(' split(val[1], tokens, ",");');
child.stdin.write(' split(tokens[2], dmitype, " ");');
child.stdin.write(' dmi = dmitype[3]+0; ');
child.stdin.write(' if(dmi == 5 || dmi == 6 || dmi == 16 || dmi == 17)');
child.stdin.write(' {');
child.stdin.write(' ccx="";');
child.stdin.write(' printf("%s{\\"%s\\": {", comma, val[2]);');
child.stdin.write(' for(j=3;j<d;++j)');
child.stdin.write(' {');
child.stdin.write(' sub(/^[ \\t]*/,"",val[j]);');
child.stdin.write(' if(split(val[j],tmp,":")>1)');
child.stdin.write(' {');
child.stdin.write(' sub(/^[ \\t]*/,"",tmp[2]);');
child.stdin.write(' gsub(/ /,"",tmp[1]);');
child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", ccx, tmp[1], tmp[2]);');
child.stdin.write(' ccx=",";');
child.stdin.write(' }');
child.stdin.write(' }');
child.stdin.write(' printf("}}");');
child.stdin.write(' comma=",";');
child.stdin.write(' }');
child.stdin.write(' }');
child.stdin.write(' printf("]");');
child.stdin.write("}'\nexit\n");
child.waitExit();
try
{
var j = JSON.parse(child.stdout.str);
var i, key, key2;
for (i = 0; i < j.length; ++i)
{
for (key in j[i])
{
delete j[i][key]['ArrayHandle'];
delete j[i][key]['ErrorInformationHandle'];
for (key2 in j[i][key])
{
if (j[i][key][key2] == 'Unknown' || j[i][key][key2] == 'Not Specified' || j[i][key][key2] == '')
{
delete j[i][key][key2];
}
}
}
}
if(j.length > 0){
var mem = {};
for (i = 0; i < j.length; ++i)
{
for (key in j[i])
{
if (mem[key] == null) { mem[key] = []; }
mem[key].push(j[i][key]);
}
}
values.linux.memory = mem;
}
}
catch (e)
{ }
child = null;
}
var usbdevices = require('lib-finder').findBinary('usb-devices');
if (usbdevices != null)
{
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stderr.str = ''; child.stderr.on('data', dataHandler);
child.stdin.write(usbdevices + " | tr '\\n' '`' | ");
child.stdin.write(" awk '");
child.stdin.write('{');
child.stdin.write(' comma="";');
child.stdin.write(' printf("[");');
child.stdin.write(' len=split($0, group, "``");');
child.stdin.write(' for(i=1;i<=len;++i)');
child.stdin.write(' {');
child.stdin.write(' comma2="";');
child.stdin.write(' xlen=split(group[i], line, "`");');
child.stdin.write(' scount=0;');
child.stdin.write(' for(x=1;x<xlen;++x)');
child.stdin.write(' {');
child.stdin.write(' if(line[x] ~ "^S:")');
child.stdin.write(' {');
child.stdin.write(' ++scount;');
child.stdin.write(' }');
child.stdin.write(' }');
child.stdin.write(' if(scount>0)');
child.stdin.write(' {');
child.stdin.write(' printf("%s{", comma); comma=",";');
child.stdin.write(' for(x=1;x<xlen;++x)');
child.stdin.write(' {');
child.stdin.write(' if(line[x] ~ "^T:")');
child.stdin.write(' {');
child.stdin.write(' comma3="";');
child.stdin.write(' printf("%s\\"hardware\\": {", comma2); comma2=",";');
child.stdin.write(' sub(/^T:[ \\t]*/, "", line[x]);');
child.stdin.write(' gsub(/= */, "=", line[x]);');
child.stdin.write(' blen=split(line[x], tokens, " ");');
child.stdin.write(' for(y=1;y<blen;++y)');
child.stdin.write(' {');
child.stdin.write(' match(tokens[y],/=/);');
child.stdin.write(' h=substr(tokens[y],1,RSTART-1);');
child.stdin.write(' v=substr(tokens[y],RSTART+1);');
child.stdin.write(' sub(/#/, "", h);');
child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", comma3, h, v); comma3=",";');
child.stdin.write(' }');
child.stdin.write(' printf("}");');
child.stdin.write(' }');
child.stdin.write(' if(line[x] ~ "^S:")');
child.stdin.write(' {');
child.stdin.write(' sub(/^S:[ \\t]*/, "", line[x]);');
child.stdin.write(' match(line[x], /=/);');
child.stdin.write(' h=substr(line[x],1,RSTART-1);');
child.stdin.write(' v=substr(line[x],RSTART+1);');
child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", comma2, h,v); comma2=",";');
child.stdin.write(' }');
child.stdin.write(' }');
child.stdin.write(' printf("}");');
child.stdin.write(' }');
child.stdin.write(' }');
child.stdin.write(' printf("]");');
child.stdin.write("}'\nexit\n");
child.waitExit();
try
{
values.linux.usb = JSON.parse(child.stdout.str);
}
catch(x)
{ }
child = null;
}
var pcidevices = require('lib-finder').findBinary('lspci');
if (pcidevices != null)
{
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stderr.str = ''; child.stderr.on('data', dataHandler);
child.stdin.write(pcidevices + " -m | tr '\\n' '`' | ");
child.stdin.write(" awk '");
child.stdin.write('{');
child.stdin.write(' printf("[");');
child.stdin.write(' comma="";');
child.stdin.write(' alen=split($0, lines, "`");');
child.stdin.write(' for(a=1;a<alen;++a)');
child.stdin.write(' {');
child.stdin.write(' match(lines[a], / /);');
child.stdin.write(' blen=split(lines[a], meta, "\\"");');
child.stdin.write(' bus=substr(lines[a], 1, RSTART);');
child.stdin.write(' gsub(/ /, "", bus);');
child.stdin.write(' printf("%s{\\"bus\\": \\"%s\\"", comma, bus); comma=",";');
child.stdin.write(' printf(", \\"device\\": \\"%s\\"", meta[2]);');
child.stdin.write(' printf(", \\"manufacturer\\": \\"%s\\"", meta[4]);');
child.stdin.write(' printf(", \\"description\\": \\"%s\\"", meta[6]);');
child.stdin.write(' if(meta[8] != "")');
child.stdin.write(' {');
child.stdin.write(' printf(", \\"subsystem\\": {");');
child.stdin.write(' printf("\\"manufacturer\\": \\"%s\\"", meta[8]);');
child.stdin.write(' printf(", \\"description\\": \\"%s\\"", meta[10]);');
child.stdin.write(' printf("}");');
child.stdin.write(' }');
child.stdin.write(' printf("}");');
child.stdin.write(' }');
child.stdin.write(' printf("]");');
child.stdin.write("}'\nexit\n");
child.waitExit();
try
{
values.linux.pci = JSON.parse(child.stdout.str);
}
catch (x)
{ }
child = null;
}
// Linux Last Boot Up Time
try {
child = require('child_process').execFile('/usr/bin/uptime', ['', '-s']); // must include blank value at begining for some reason?
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stderr.on('data', function () { });
child.waitExit();
var regex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
if (regex.test(child.stdout.str.trim())) {
values.linux.LastBootUpTime = child.stdout.str.trim();
} else {
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('date -d "@$(( $(date +%s) - $(awk \'{print int($1)}\' /proc/uptime) ))" "+%Y-%m-%d %H:%M:%S"\nexit\n');
child.waitExit();
if (regex.test(child.stdout.str.trim())) {
values.linux.LastBootUpTime = child.stdout.str.trim();
}
}
child = null;
} catch (ex) { }
// Linux TPM
try {
if (require('fs').statSync('/sys/class/tpm/tpm0').isDirectory()){
values.tpm = {
SpecVersion: require('fs').readFileSync('/sys/class/tpm/tpm0/tpm_version_major').toString().trim()
}
}
} catch (ex) { }
return (values);
}
function windows_wmic_results(str)
{
var lines = str.trim().split('\r\n');
var keys = lines[0].split(',');
var i, key, keyval;
var tokens;
var result = [];
console.log('Lines: ' + lines.length, 'Keys: ' + keys.length);
for (i = 1; i < lines.length; ++i)
{
var obj = {};
console.log('i: ' + i);
tokens = lines[i].split(',');
for (key = 0; key < keys.length; ++key)
{
var tmp = Buffer.from(tokens[key], 'binary').toString();
console.log(tokens[key], tmp);
tokens[key] = tmp == null ? '' : tmp;
if (tokens[key].trim())
{
obj[keys[key].trim()] = tokens[key].trim();
}
}
delete obj.Node;
result.push(obj);
}
return (result);
}
function windows_identifiers()
{
var ret = { windows: {} };
var items, item, i;
ret['identifiers'] = {};
var values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_Bios", ['ReleaseDate', 'Manufacturer', 'SMBIOSBIOSVersion', 'SerialNumber']);
if(values[0]){
ret['identifiers']['bios_date'] = values[0]['ReleaseDate'];
ret['identifiers']['bios_vendor'] = values[0]['Manufacturer'];
ret['identifiers']['bios_version'] = values[0]['SMBIOSBIOSVersion'];
ret['identifiers']['bios_serial'] = values[0]['SerialNumber'];
}
ret['identifiers']['bios_mode'] = 'Legacy';
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_BaseBoard", ['Product', 'SerialNumber', 'Manufacturer', 'Version']);
if(values[0]){
ret['identifiers']['board_name'] = values[0]['Product'];
ret['identifiers']['board_serial'] = values[0]['SerialNumber'];
ret['identifiers']['board_vendor'] = values[0]['Manufacturer'];
ret['identifiers']['board_version'] = values[0]['Version'];
}
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_ComputerSystemProduct", ['UUID', 'Name']);
if(values[0]){
ret['identifiers']['product_uuid'] = values[0]['UUID'];
ret['identifiers']['product_name'] = values[0]['Name'];
trimIdentifiers(ret.identifiers);
}
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_PhysicalMemory");
if(values[0]){
trimResults(values);
ret.windows.memory = values;
}
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_OperatingSystem");
if(values[0]){
trimResults(values);
ret.windows.osinfo = values[0];
}
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_DiskPartition");
if(values[0]){
trimResults(values);
ret.windows.partitions = values;
for (var i in values) {
if (values[i].Description=='GPT: System') {
ret['identifiers']['bios_mode'] = 'UEFI';
}
}
}
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_Processor", ['Caption', 'DeviceID', 'Manufacturer', 'MaxClockSpeed', 'Name', 'SocketDesignation']);
if(values[0]){
ret.windows.cpu = values;
}
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_VideoController", ['Name', 'CurrentHorizontalResolution', 'CurrentVerticalResolution']);
if(values[0]){
ret.windows.gpu = values;
}
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_DiskDrive", ['Caption', 'DeviceID', 'Model', 'Partitions', 'Size', 'Status']);
if(values[0]){
ret.windows.drives = values;
}
// Insert GPU names
ret.identifiers.gpu_name = [];
for (var gpuinfo in ret.windows.gpu)
{
if (ret.windows.gpu[gpuinfo].Name) { ret.identifiers.gpu_name.push(ret.windows.gpu[gpuinfo].Name); }
}
// Insert Storage Devices
ret.identifiers.storage_devices = [];
for (var dv in ret.windows.drives)
{
ret.identifiers.storage_devices.push({ Caption: ret.windows.drives[dv].Caption, Model: ret.windows.drives[dv].Model, Size: ret.windows.drives[dv].Size });
}
try { ret.identifiers.cpu_name = ret.windows.cpu[0].Name; } catch (x) { }
// Windows TPM
IntToStr = function (v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
try {
values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftTpm', "SELECT * FROM Win32_Tpm", ['IsActivated_InitialValue','IsEnabled_InitialValue','IsOwned_InitialValue','ManufacturerId','ManufacturerVersion','SpecVersion']);
if(values[0]) {
ret.tpm = {
SpecVersion: values[0].SpecVersion.split(",")[0],
ManufacturerId: IntToStr(values[0].ManufacturerId).replace(/[^\x00-\x7F]/g, ""),
ManufacturerVersion: values[0].ManufacturerVersion,
IsActivated: values[0].IsActivated_InitialValue,
IsEnabled: values[0].IsEnabled_InitialValue,
IsOwned: values[0].IsOwned_InitialValue,
}
}
} catch (ex) { }
return (ret);
}
function macos_identifiers()
{
var ret = { identifiers: {}, darwin: {} };
var child;
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep board-id | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
child.waitExit();
ret.identifiers.board_name = child.stdout.str.trim();
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformSerialNumber | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
child.waitExit();
ret.identifiers.board_serial = child.stdout.str.trim();
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep manufacturer | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
child.waitExit();
ret.identifiers.board_vendor = child.stdout.str.trim();
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep version | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
child.waitExit();
ret.identifiers.board_version = child.stdout.str.trim();
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformUUID | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
child.waitExit();
ret.identifiers.product_uuid = child.stdout.str.trim();
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('sysctl -n machdep.cpu.brand_string\nexit\n');
child.waitExit();
ret.identifiers.cpu_name = child.stdout.str.trim();
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('system_profiler SPMemoryDataType\nexit\n');
child.waitExit();
var lines = child.stdout.str.trim().split('\n');
if(lines.length > 0) {
const memorySlots = [];
if(lines[2].trim().includes('Memory Slots:')) { // OLD MACS WITH SLOTS
var memorySlots1 = child.stdout.str.split(/\n{2,}/).slice(3);
memorySlots1.forEach(function(slot,index) {
var lines = slot.split('\n');
if(lines.length == 1){ // start here
if(lines[0].trim()!=''){
var slotObj = { DeviceLocator: lines[0].trim().replace(/:$/, '') }; // Initialize name as an empty string
var nextline = memorySlots1[index+1].split('\n');
nextline.forEach(function(line) {
if (line.trim() !== '') {
var parts = line.split(':');
var key = parts[0].trim();
var value = parts[1].trim();
value = (key == 'Part Number' || key == 'Manufacturer') ? hexToAscii(parts[1].trim()) : parts[1].trim();
slotObj[key.replace(' ','')] = value; // Store attribute in the slot object
}
});
memorySlots.push(slotObj);
}
}
});
} else { // NEW MACS WITHOUT SLOTS
memorySlots.push({ DeviceLocator: "Onboard Memory", Size: lines[2].split(":")[1].trim(), PartNumber: lines[3].split(":")[1].trim(), Manufacturer: lines[4].split(":")[1].trim() })
}
ret.darwin.memory = memorySlots;
}
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('diskutil info -all\nexit\n');
child.waitExit();
var sections = child.stdout.str.split('**********\n');
if(sections.length > 0){
var devices = [];
for (var i = 0; i < sections.length; i++) {
var lines = sections[i].split('\n');
var deviceInfo = {};
var wholeYes = false;
var physicalYes = false;
var oldmac = false;
for (var j = 0; j < lines.length; j++) {
var keyValue = lines[j].split(':');
var key = keyValue[0].trim();
var value = keyValue[1] ? keyValue[1].trim() : '';
if (key === 'Virtual') oldmac = true;
if (key === 'Whole' && value === 'Yes') wholeYes = true;
if (key === 'Virtual' && value === 'No') physicalYes = true;
if(value && key === 'Device / Media Name'){
deviceInfo['Caption'] = value;
}
if(value && key === 'Disk Size'){
deviceInfo['Size'] = value.split(' ')[0] + ' ' + value.split(' ')[1];
}
}
if (wholeYes) {
if (oldmac) {
if (physicalYes) devices.push(deviceInfo);
} else {
devices.push(deviceInfo);
}
}
}
ret.identifiers.storage_devices = devices;
}
// Fetch storage volumes using df
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write('df -aHY | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $3, $4, $5, $10, $2}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n');
child.waitExit();
try {
ret.darwin.volumes = JSON.parse(child.stdout.str.trim());
for (var index = 0; index < ret.darwin.volumes.length; index++) {
if (ret.darwin.volumes[index].type == 'auto_home'){
ret.darwin.volumes.splice(index,1);
}
}
if (ret.darwin.volumes.length == 0) { // not sonima OS so dont show type for now
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', dataHandler);
child.stdin.write('df -aH | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\"},", $2, $3, $4, $9}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n');
child.waitExit();
try {
ret.darwin.volumes = JSON.parse(child.stdout.str.trim());
for (var index = 0; index < ret.darwin.volumes.length; index++) {
if (ret.darwin.volumes[index].size == 'auto_home'){
ret.darwin.volumes.splice(index,1);
}
}
} catch (xx) { }
}
} catch (xx) { }
child = null;
// MacOS Last Boot Up Time
try {
child = require('child_process').execFile('/usr/sbin/sysctl', ['', 'kern.boottime']); // must include blank value at begining for some reason?
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stderr.on('data', function () { });
child.waitExit();
const timestampMatch = /\{ sec = (\d+), usec = \d+ \}/.exec(child.stdout.str.trim());
if (!ret.darwin) {
ret.darwin = { LastBootUpTime: parseInt(timestampMatch[1]) };
} else {
ret.darwin.LastBootUpTime = parseInt(timestampMatch[1]);
}
child = null;
} catch (ex) { }
trimIdentifiers(ret.identifiers);
child = null;
return (ret);
}
function hexToAscii(hexString) {
if(!hexString.startsWith('0x')) return hexString.trim();
hexString = hexString.startsWith('0x') ? hexString.slice(2) : hexString;
var str = '';
for (var i = 0; i < hexString.length; i += 2) {
var hexPair = hexString.substr(i, 2);
str += String.fromCharCode(parseInt(hexPair, 16));
}
str = str.replace(/[\u007F-\uFFFF]/g, ''); // Remove characters from 0x0080 to 0xFFFF
return str.trim();
}
function win_chassisType()
{
// needs to be replaced with win-wmi but due to bug in win-wmi it doesnt handle arrays correctly
var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
if (child == null) { return ([]); }
child.descriptorMetadata = 'process-manager';
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
child.stdin.write('Get-WmiObject Win32_SystemEnclosure | Select-Object -ExpandProperty ChassisTypes\r\n');
child.stdin.write('exit\r\n');
child.waitExit();
try {
return (parseInt(child.stdout.str));
} catch (e) {
return (2); // unknown
}
}
function win_systemType()
{
try {
var tokens = require('win-wmi').query('ROOT\\CIMV2', 'SELECT PCSystemType FROM Win32_ComputerSystem', ['PCSystemType']);
if (tokens[0]) {
return (parseInt(tokens[0]['PCSystemType']));
} else {
return (parseInt(1)); // default is desktop
}
} catch (ex) {
return (parseInt(1)); // default is desktop
}
}
function win_formFactor(chassistype)
{
var ret = 'DESKTOP';
switch (chassistype)
{
case 11: // Handheld
case 30: // Tablet
case 31: // Convertible
case 32: // Detachable
ret = 'TABLET';
break;
case 9: // Laptop
case 10: // Notebook
case 14: // Sub Notebook
ret = 'LAPTOP';
break;
default:
ret = win_systemType() == 2 ? 'MOBILE' : 'DESKTOP';
break;
}
return (ret);
}
switch(process.platform)
{
case 'linux':
module.exports = { _ObjectID: 'identifiers', get: linux_identifiers };
break;
case 'win32':
module.exports = { _ObjectID: 'identifiers', get: windows_identifiers, chassisType: win_chassisType, formFactor: win_formFactor, systemType: win_systemType };
break;
case 'darwin':
module.exports = { _ObjectID: 'identifiers', get: macos_identifiers };
break;
default:
module.exports = { get: function () { throw ('Unsupported Platform'); } };
break;
}
module.exports.isDocker = function isDocker()
{
if (process.platform != 'linux') { return (false); }
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write("cat /proc/self/cgroup | tr '\n' '`' | awk -F'`' '{ split($1, res, " + '"/"); if(res[2]=="docker"){print "1";} }\'\nexit\n');
child.waitExit();
return (child.stdout.str != '');
};
module.exports.isBatteryPowered = function isBatteryOperated()
{
var ret = false;
switch(process.platform)
{
default:
break;
case 'linux':
var devices = require('fs').readdirSync('/sys/class/power_supply');
for (var i in devices)
{
if (require('fs').readFileSync('/sys/class/power_supply/' + devices[i] + '/type').toString().trim() == 'Battery')
{
ret = true;
break;
}
}
break;
case 'win32':
var GM = require('_GenericMarshal');
var stats = GM.CreateVariable(12);
var kernel32 = GM.CreateNativeProxy('Kernel32.dll');
kernel32.CreateMethod('GetSystemPowerStatus');
if (kernel32.GetSystemPowerStatus(stats).Val != 0)
{
if(stats.toBuffer()[1] != 128 && stats.toBuffer()[1] != 255)
{
ret = true;
}
else
{
// No Battery detected, so lets check if there is supposed to be one
var formFactor = win_formFactor(win_chassisType());
return (formFactor == 'LAPTOP' || formFactor == 'TABLET' || formFactor == 'MOBILE');
}
}
break;
case 'darwin':
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function(c){ this.str += c.toString(); });
child.stderr.str = ''; child.stderr.on('data', function(c){ this.str += c.toString(); });
child.stdin.write("pmset -g batt | tr '\\n' '`' | awk -F'`' '{ if(NF>2) { print \"true\"; }}'\nexit\n");
child.waitExit();
if(child.stdout.str.trim() != '') { ret = true; }
break;
}
return (ret);
};
module.exports.isVM = function isVM()
{
var ret = false;
var id = this.get();
if (id.linux && id.linux.sys_vendor)
{
switch (id.linux.sys_vendor)
{
case 'VMware, Inc.':
case 'QEMU':
case 'Xen':
ret = true;
break;
default:
break;
}
}
if (id.identifiers.bios_vendor)
{
switch(id.identifiers.bios_vendor)
{
case 'VMware, Inc.':
case 'Xen':
case 'SeaBIOS':
case 'EFI Development Kit II / OVMF':
case 'Proxmox distribution of EDK II':
ret = true;
break;
default:
break;
}
}
if (id.identifiers.board_vendor && id.identifiers.board_vendor == 'VMware, Inc.') { ret = true; }
if (id.identifiers.board_name)
{
switch (id.identifiers.board_name)
{
case 'VirtualBox':
case 'Virtual Machine':
ret = true;
break;
default:
break;
}
}
if (process.platform == 'win32' && !ret)
{
for(var i in id.identifiers.gpu_name)
{
if(id.identifiers.gpu_name[i].startsWith('VMware '))
{
ret = true;
break;
}
}
}
if (!ret) { ret = this.isDocker(); }
return (ret);
};
// bios_date = BIOS->ReleaseDate
// bios_vendor = BIOS->Manufacturer
// bios_version = BIOS->SMBIOSBIOSVersion
// board_name = BASEBOARD->Product = ioreg/board-id
// board_serial = BASEBOARD->SerialNumber = ioreg/serial-number | ioreg/IOPlatformSerialNumber
// board_vendor = BASEBOARD->Manufacturer = ioreg/manufacturer
// board_version = BASEBOARD->Version

View file

@ -135,12 +135,12 @@
"allow": "Permitir", "allow": "Permitir",
"deny": "Negar", "deny": "Negar",
"autoAllowForFive": "Aceita automaticamente todas as conexões pelos próximos 5 minutos", "autoAllowForFive": "Aceita automaticamente todas as conexões pelos próximos 5 minutos",
"terminalConsent": "{0} está a pedir acesso ao terminal remoto. Conceder acesso?", "terminalConsent": "{0} solicitando acesso ao terminal remoto. Garantir acesso?",
"desktopConsent": "{0} está a pedir acesso à área de trabalho remota. Conceder acesso?", "desktopConsent": "{0} solicitando acesso à área de trabalho remota. Garantir acesso?",
"fileConsent": "{0} está a pedir acesso remoto aos ficheiros. Conceder acesso?", "fileConsent": "{0} solicitando acesso remoto ao arquivo. Garantir acesso?",
"terminalNotify": "{0} iniciou uma sessão de terminal remoto.", "terminalNotify": "{0} iniciou uma sessão de terminal remoto.",
"desktopNotify": "{0} iniciou uma sessão de área de trabalho remota.", "desktopNotify": "{0} iniciou uma sessão de área de trabalho remota.",
"fileNotify": "{0} iniciou uma sessão de ficheiro remoto.", "fileNotify": "{0} iniciou uma sessão de arquivo remoto.",
"privacyBar": "Compartilhando área de trabalho com: {0}" "privacyBar": "Compartilhando área de trabalho com: {0}"
}, },
"ru": { "ru": {
@ -238,53 +238,5 @@
"desktopNotify": "{0} 啟動了遠程桌面會話。", "desktopNotify": "{0} 啟動了遠程桌面會話。",
"fileNotify": "{0} 啟動了遠程文件會話。", "fileNotify": "{0} 啟動了遠程文件會話。",
"privacyBar": "與:{0} 共享桌面" "privacyBar": "與:{0} 共享桌面"
},
"bs": {
"allow": "Dopustiti",
"deny": "Deny",
"autoAllowForFive": "Automatski prihvati sve veze u narednih 5 minuta",
"terminalConsent": "{0} zahtijeva pristup udaljenom terminalu. Odobriti pristup?",
"desktopConsent": "{0} zahtijeva pristup udaljenoj radnoj površini. Odobriti pristup?",
"fileConsent": "{0} zahtijeva udaljeni pristup fajlu. Odobriti pristup?",
"terminalNotify": "{0} je započeo sesiju udaljenog terminala.",
"desktopNotify": "{0} je započeo sesiju udaljene radne površine.",
"fileNotify": "{0} je započeo sesiju udaljenog fajla.",
"privacyBar": "Dijeljenje radne površine sa: {0}"
},
"hu": {
"allow": "Engedélyezés",
"deny": "Elutasítás",
"autoAllowForFive": "Csatlakozások automatikus elfogadása a következő 5 percben",
"terminalConsent": "{0} távoli parancssor,terminál hozzáférést kér. Engedélyezi a hozzáférést?",
"desktopConsent": "{0} távoli asztali hozzáférést kér. Engedélyezi a hozzáférést?",
"fileConsent": "{0} távoli fájlhozzáférést kér. Engedélyezi a hozzáférést?",
"terminalNotify": "{0} távoli parancssor munkamenetet indított.",
"desktopNotify": "{0} távoli asztali munkamenetet indított.",
"fileNotify": "{0} távoli fájlmunkamenetet indított.",
"privacyBar": "Asztal megosztás aktív: {0} felhasználóval"
},
"ca": {
"allow": "Permetre",
"deny": "Negar",
"autoAllowForFive": "Accepta automàticament totes les connexions durant els propers 5 minuts",
"terminalConsent": "{0} sol·licitant accés al terminal remot. Accés garantit?",
"desktopConsent": "{0} sol·licitant accés a l'escriptori remot. Accés garantit?",
"fileConsent": "{0} sol·licitant accés remot al fitxer. Accés garantit?",
"terminalNotify": "{0} va iniciar una sessió de terminal remota.",
"desktopNotify": "{0} va iniciar una sessió d'escriptori remot.",
"fileNotify": "{0} va iniciar una sessió de fitxer remota.",
"privacyBar": "Compartint escriptori amb: {0}"
},
"uk": {
"allow": "Дозволити",
"deny": "Відмовити",
"autoAllowForFive": "Автоматично приймати всі підключення впродовж наступних 5 хвилин",
"terminalConsent": "{0} запитує доступ до віддаленого терміналу. Надати доступ?",
"desktopConsent": "{0} запитує віддалений доступ до стільниці. Надати доступ?",
"fileConsent": "{0} запитує віддалений доступ до файлу. Надати доступ?",
"terminalNotify": "{0} почав сеанс віддаленого терміналу.",
"desktopNotify": "{0} розпочав сеанс віддаленої стільниці.",
"fileNotify": "{0} розпочав віддалений файловий сеанс.",
"privacyBar": "Поширити доступ до стільниці з: {0}"
} }
} }

View file

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

View file

@ -159,7 +159,7 @@ function linux_memUtilization()
case 'MemTotal:': case 'MemTotal:':
ret.total = parseInt(tokens[tokens.length - 2]); ret.total = parseInt(tokens[tokens.length - 2]);
break; break;
case 'MemAvailable:': case 'MemFree:':
ret.free = parseInt(tokens[tokens.length - 2]); ret.free = parseInt(tokens[tokens.length - 2]);
break; break;
} }
@ -209,13 +209,9 @@ function macos_memUtilization()
{ {
var usage = lines[0].split(':')[1]; var usage = lines[0].split(':')[1];
var bdown = usage.split(','); var bdown = usage.split(',');
if (bdown.length > 2){ // new style - PhysMem: 5750M used (1130M wired, 634M compressor), 1918M unused.
mem.MemFree = parseInt(bdown[2].trim().split(' ')[0]); mem.MemTotal = parseInt(bdown[0].trim().split(' ')[0]);
} else { // old style - PhysMem: 6683M used (1606M wired), 9699M unused. mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]);
mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]);
}
mem.MemUsed = parseInt(bdown[0].trim().split(' ')[0]);
mem.MemTotal = (mem.MemFree + mem.MemUsed);
mem.percentFree = ((mem.MemFree / mem.MemTotal) * 100);//.toFixed(2); mem.percentFree = ((mem.MemFree / mem.MemTotal) * 100);//.toFixed(2);
mem.percentConsumed = (((mem.MemTotal - mem.MemFree) / mem.MemTotal) * 100);//.toFixed(2); mem.percentConsumed = (((mem.MemTotal - mem.MemFree) / mem.MemTotal) * 100);//.toFixed(2);
return (mem); return (mem);
@ -229,48 +225,31 @@ function macos_memUtilization()
function windows_thermals() function windows_thermals()
{ {
var ret = []; var ret = [];
try { child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', '/namespace:\\\\root\\wmi', 'PATH', 'MSAcpi_ThermalZoneTemperature', 'get', 'CurrentTemperature']);
ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
if (ret[0]) { child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
for (var i = 0; i < ret.length; ++i) { child.waitExit();
ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2);
} if(child.stdout.str.trim!='')
{
var lines = child.stdout.str.trim().split('\r\n');
for (var i = 1; i < lines.length; ++i)
{
if (lines[i].trim() != '') { ret.push(((parseFloat(lines[i]) / 10) - 273.15).toFixed(2)); }
} }
} catch (ex) { } }
return (ret); return (ret);
} }
function linux_thermals() function linux_thermals()
{ {
var ret = [];
child = require('child_process').execFile('/bin/sh', ['sh']); child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); }); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); }); child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
child.stdin.write("for folder in /sys/class/thermal/thermal_zone*/; do [ -e \"$folder/temp\" ] && echo \"$(cat \"$folder/temp\"),$(cat \"$folder/type\")\"; done\nexit\n"); child.stdin.write("cat /sys/class/thermal/thermal_zone*/temp | awk '{ print $0 / 1000 }'\nexit\n");
child.waitExit(); child.waitExit();
if(child.stdout.str.trim()!='') var ret = child.stdout.str.trim().split('\n');
{ if (ret.length == 1 && ret[0] == '') { ret = []; }
var lines = child.stdout.str.trim().split('\n');
for (var i = 0; i < lines.length; ++i)
{
var line = lines[i].trim().split(',');
ret.push({CurrentTemperature: (parseFloat(line[0])/1000), InstanceName: line[1]});
}
}
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
child.stdin.write("for mon in /sys/class/hwmon/hwmon*; do for label in \"$mon\"/temp*_label; do if [ -f $label ]; then echo $(cat \"$label\")___$(cat \"${label%_*}_input\"); fi; done; done;\nexit\n");
child.waitExit();
if(child.stdout.str.trim()!='')
{
var lines = child.stdout.str.trim().split('\n');
for (var i = 0; i < lines.length; ++i)
{
var line = lines[i].trim().split('___');
ret.push({ CurrentTemperature: (parseFloat(line[1])/1000), InstanceName: line[0] });
}
}
return (ret); return (ret);
} }
@ -282,6 +261,7 @@ function macos_thermals()
child.stderr.on('data', function () { }); child.stderr.on('data', function () { });
child.stdin.write('powermetrics --help | grep SMC\nexit\n'); child.stdin.write('powermetrics --help | grep SMC\nexit\n');
child.waitExit(); child.waitExit();
if (child.stdout.str.trim() != '') if (child.stdout.str.trim() != '')
{ {
child = require('child_process').execFile('/bin/sh', ['sh']); child = require('child_process').execFile('/bin/sh', ['sh']);
@ -293,19 +273,14 @@ function macos_thermals()
{ {
if (tokens[i].split(' die temperature: ').length > 1) if (tokens[i].split(' die temperature: ').length > 1)
{ {
ret.push({CurrentTemperature: tokens[i].split(' ')[3], InstanceName: tokens[i].split(' ')[0]}); ret.push(tokens[i].split(' ')[3]);
this.parent.kill(); this.parent.kill();
} }
} }
}); });
child.stderr.on('data', function (c) { child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
if (c.toString().split('unable to get smc values').length > 1) { // error getting sensors so just kill child.stdin.write('powermetrics -s smc\n');
this.parent.kill(); child.waitExit(5000);
return;
}
});
child.stdin.write('powermetrics -s smc -i 500 -n 1\n');
child.waitExit(2000);
} }
return (ret); return (ret);
} }

View file

@ -1,194 +0,0 @@
/*
Copyright 2022 Intel Corporation
@author Bryan Roe
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
//
// win-deskutils is a utility module that exposes various desktop related features for Windows
// such as MouseTrails Accessability and Windows Desktop Background
//
//
// MSDN documention for the system call this module relies on can be found at:
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
//
var SPI_GETDESKWALLPAPER = 0x0073;
var SPI_SETDESKWALLPAPER = 0x0014;
var SPI_GETMOUSETRAILS = 0x005E;
var SPI_SETMOUSETRAILS = 0x005D;
var GM = require('_GenericMarshal');
var user32 = GM.CreateNativeProxy('user32.dll');
user32.CreateMethod('SystemParametersInfoA');
//
// This function is a helper method to dispatch method calls to different user sessions
//
function sessionDispatch(tsid, parent, method, args)
{
//
// Check to see if the process owner of the current processor is root
//
var sid = undefined;
var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
/*
The following is the list of possible values for stype.
If the current process owner is root, we set the stype to user,
because we cannot set/get any properties from this user, we
must switch to a user session.. Default behavior for stype(1)
is that it will context switch to the logged in user. If
this is not intended, then an actual user TSID must be specified, using
ILibProcessPipe_SpawnTypes_SPECIFIED_USER and the actual TSID
------------------------------------------------------------------------
ILibProcessPipe_SpawnTypes_DEFAULT = 0,
ILibProcessPipe_SpawnTypes_USER = 1,
ILibProcessPipe_SpawnTypes_WINLOGON = 2,
ILibProcessPipe_SpawnTypes_TERM = 3,
ILibProcessPipe_SpawnTypes_DETACHED = 4,
ILibProcessPipe_SpawnTypes_SPECIFIED_USER = 5,
ILibProcessPipe_SpawnTypes_POSIX_DETACHED = 0x8000
------------------------------------------------------------------------
*/
console.log('stype: ' + stype);
if (stype == 1)
{
if (tsid == null && require('MeshAgent')._tsid != null)
{
stype = 5; // ILibProcessPipe_SpawnTypes_SPECIFIED_USER
sid = require('MeshAgent')._tsid; // If this is set, it was set via user selection UI
}
else
{
sid = tsid; // Set the SID to be whatever was passed in
}
}
// Spawn a child process in the appropriate user session, and relay the response back via stdout
var mod = Buffer.from(getJSModule('win-deskutils')).toString('base64');
var prog = "try { addModule('win-deskutils', process.env['win_deskutils']);} catch (x) { } var x;try{x=require('win-deskutils').dispatch('" + parent + "', '" + method + "', " + JSON.stringify(args) + ");console.log(x);}catch(z){console.log(z);process.exit(1);}process.exit(0);";
var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', Buffer.from(prog).toString('base64')], { type: stype, uid: sid, env: { win_deskutils: getJSModule('win-deskutils') } });
child.stdout.str = '';
child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stderr.on('data', function (c) { });
child.on('exit', function (c) { this.exitCode = c; });
child.waitExit();
if (child.exitCode == 0)
{
return (child.stdout.str.trim()); // If the return code was 0, then relay the response from stdout
}
else
{
throw (child.stdout.str.trim()); // If the return code was nonzero, then the stdout response is the exception that should be bubbled
}
}
//
// This function gets the path of the windows desktop background of the specified user desktop session
//
function background_get(tsid)
{
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'background', 'get', []));
}
var v = GM.CreateVariable(1024);
var ret = user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER, v._size, v, 0);
if (ret.Val == 0)
{
throw ('Error occured trying to fetch wallpaper');
}
return (v.String);
}
//
// This function sets the path for the windows desktop background of the specified user desktop session
//
function background_set(path, tsid)
{
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'background', 'set', [path]));
}
var nb = GM.CreateVariable(path);
var ret = user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, nb._size, nb, 0);
if (ret.Val == 0)
{
throw ('Error occured trying to set wallpaper');
}
return;
}
//
// This is a helper function that is called by the child process from sessionDispatch()
//
function dispatch(parent, method, args)
{
try
{
return (this[parent][method].apply(this, args));
}
catch (e)
{
console.log('ERROR: ' + e);
throw ('Error occured trying to dispatch: ' + method);
}
}
//
// This function sets the mousetrail accessibility feature, for the specified user desktop session.
// Setting value 0 or one disables this feature
// Otherwise, value is the number of cursors to render for this feature
//
function mousetrails_set(value, tsid)
{
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'mouse', 'setTrails', [value]));
}
var ret = user32.SystemParametersInfoA(SPI_SETMOUSETRAILS, value, 0, 0);
if (ret.Val == 0)
{
throw ('Error occured trying to fetch wallpaper');
}
}
//
// This function returns the number of cursors the mousetrail accessibility feature will render
// A value of 0 or 1 means the feature is disabled, otherwise it is the number of cursors that will be rendered
//
function mousetrails_get(tsid)
{
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
{
// Need to disatch to different session first
return (sessionDispatch(tsid, 'mouse', 'getTrails', []));
}
var v = GM.CreateVariable(4);
var ret = user32.SystemParametersInfoA(SPI_GETMOUSETRAILS, v._size, v, 0);
if (ret.Val == 0)
{
throw ('Error occured trying to fetch wallpaper');
}
return (v.toBuffer().readUInt32LE());
}
module.exports = { background: { get: background_get, set: background_set } };
module.exports.mouse = { getTrails: mousetrails_get, setTrails: mousetrails_set };
module.exports.dispatch = dispatch;

View file

@ -18,21 +18,28 @@ var promise = require('promise');
function qfe() function qfe()
{ {
try { var child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', 'qfe', 'list', 'full', '/FORMAT:CSV']);
var tokens = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_QuickFixEngineering'); child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
if (tokens[0]){ child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
for (var index = 0; index < tokens.length; index++) { child.waitExit();
for (var key in tokens[index]) {
if (key.startsWith('__')) delete tokens[index][key]; var lines = child.stdout.str.trim().split('\r\n');
} var keys = lines[0].split(',');
} var i, key;
return (tokens); var tokens;
} else { var result = [];
return ([]);
for (i = 1; i < lines.length; ++i)
{
var obj = {};
tokens = lines[i].split(',');
for (key = 0; key < keys.length; ++key)
{
if (tokens[key]) { obj[keys[key]] = tokens[key]; }
} }
} catch (ex) { result.push(obj);
return ([]);
} }
return (result);
} }
function av() function av()
{ {
@ -46,23 +53,9 @@ function av()
child.stdin.write('[reflection.Assembly]::LoadWithPartialName("system.core")\r\n'); child.stdin.write('[reflection.Assembly]::LoadWithPartialName("system.core")\r\n');
child.stdin.write('Get-WmiObject -Namespace "root/SecurityCenter2" -Class AntiVirusProduct | '); child.stdin.write('Get-WmiObject -Namespace "root/SecurityCenter2" -Class AntiVirusProduct | ');
child.stdin.write('ForEach-Object -Process { '); child.stdin.write('ForEach-Object -Process { ');
child.stdin.write('$matches = [regex]::Matches($_.pathToSignedProductExe, "%(.*?)%"); ');
child.stdin.write('$modifiedPath = $_.pathToSignedProductExe; ');
child.stdin.write('foreach ($match in $matches) { ');
child.stdin.write('$modifiedPath = $modifiedPath -replace [regex]::Escape($match.Value), [System.Environment]::GetEnvironmentVariable($match.Groups[1].Value, "Process") ');
child.stdin.write('} ');
child.stdin.write('$flag = $true; ');
child.stdin.write('if ($modifiedPath -ne "windowsdefender://"){ ');
child.stdin.write('if (-not (Test-Path -Path $modifiedPath -PathType Leaf)) { ');
child.stdin.write('$flag = $false; ');
child.stdin.write('} ');
child.stdin.write('} ');
child.stdin.write('if ($flag -eq $true) { ')
child.stdin.write('$Bytes = [System.Text.Encoding]::UTF8.GetBytes($_.displayName); '); child.stdin.write('$Bytes = [System.Text.Encoding]::UTF8.GetBytes($_.displayName); ');
child.stdin.write('$EncodedText =[Convert]::ToBase64String($Bytes); '); child.stdin.write('$EncodedText =[Convert]::ToBase64String($Bytes); ');
child.stdin.write('Write-Output ("{0},{1}" -f $_.productState,$EncodedText); '); child.stdin.write('Write-Host ("{0},{1}" -f $_.productState,$EncodedText); }\r\n');
child.stdin.write('} ');
child.stdin.write('}\r\n ');
child.stdin.write('exit\r\n'); child.stdin.write('exit\r\n');
child.waitExit(); child.waitExit();
@ -221,14 +214,6 @@ function installedApps()
catch(e)\ catch(e)\
{\ {\
}\ }\
try\
{\
val.installdate = reg.QueryKey(reg.HKEY.LocalMachine, 'SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\' + items.subkeys[key], 'InstallDate');\
if (val.installdate == '') { delete val.installdate; }\
}\
catch(e)\
{\
}\
result.push(val);\ result.push(val);\
}\ }\
console.log(JSON.stringify(result,'', 1));process.exit();"; console.log(JSON.stringify(result,'', 1));process.exit();";
@ -240,33 +225,12 @@ function installedApps()
return (ret); return (ret);
} }
function defender(){
var promise = require('promise');
var ret = new promise(function (a, r) { this._resolve = a; this._reject = r; });
ret.child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
ret.child.promise = ret;
ret.child.stdout.str = ''; ret.child.stdout.on('data', function (c) { this.str += c.toString(); });
ret.child.stderr.str = ''; ret.child.stderr.on('data', function (c) { this.str += c.toString(); });
ret.child.stdin.write('Get-MpComputerStatus | Select-Object RealTimeProtectionEnabled,IsTamperProtected | ConvertTo-JSON\r\n');
ret.child.stdin.write('exit\r\n');
ret.child.on('exit', function (c) {
if (this.stdout.str == '') { this.promise._resolve({}); return; }
try {
var abc = JSON.parse(this.stdout.str.trim());
this.promise._resolve({ RealTimeProtection: abc.RealTimeProtectionEnabled, TamperProtected: abc.IsTamperProtected });
} catch (ex) {
this.promise._resolve({}); return;
}
});
return (ret);
}
if (process.platform == 'win32') if (process.platform == 'win32')
{ {
module.exports = { qfe: qfe, av: av, defrag: defrag, pendingReboot: pendingReboot, installedApps: installedApps, defender: defender }; module.exports = { qfe: qfe, av: av, defrag: defrag, pendingReboot: pendingReboot, installedApps: installedApps };
} }
else else
{ {
var not_supported = function () { throw (process.platform + ' not supported'); }; var not_supported = function () { throw (process.platform + ' not supported'); };
module.exports = { qfe: not_supported, av: not_supported, defrag: not_supported, pendingReboot: not_supported, installedApps: not_supported, defender: not_supported }; module.exports = { qfe: not_supported, av: not_supported, defrag: not_supported, pendingReboot: not_supported, installedApps: not_supported };
} }

View file

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

View file

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

View file

@ -39,90 +39,17 @@ function getVolumes()
{ {
ret[v[i].DeviceID] = trimObject(v[i]); ret[v[i].DeviceID] = trimObject(v[i]);
} }
try {
v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume'); v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume');
for (i in v) for (i in v)
{
var tmp = trimObject(v[i]);
for (var k in tmp)
{ {
var tmp = trimObject(v[i]); ret[tmp.DeviceID][k] = tmp[k];
for (var k in tmp)
{
ret[tmp.DeviceID][k] = tmp[k];
}
} }
} catch (ex) { } }
return (ret); return (ret);
} }
function windows_volumes() module.exports = { getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } } };
{
var promise = require('promise');
var p1 = new promise(function (res, rej) { this._res = res; this._rej = rej; });
var ret = {};
var values = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_LogicalDisk', ['DeviceID', 'VolumeName', 'FileSystem', 'Size', 'FreeSpace', 'DriveType']);
if(values[0]){
for (var i = 0; i < values.length; ++i) {
var drive = values[i]['DeviceID'].slice(0,-1);
ret[drive] = {
name: (values[i]['VolumeName'] ? values[i]['VolumeName'] : ""),
type: (values[i]['FileSystem'] ? values[i]['FileSystem'] : "Unknown"),
size: (values[i]['Size'] ? values[i]['Size'] : 0),
sizeremaining: (values[i]['FreeSpace'] ? values[i]['FreeSpace'] : 0),
removable: (values[i]['DriveType'] == 2),
cdrom: (values[i]['DriveType'] == 5)
};
}
}
try {
values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume', ['DriveLetter','ConversionStatus','ProtectionStatus']);
if(values[0]){
for (var i = 0; i < values.length; ++i) {
var drive = values[i]['DriveLetter'].slice(0,-1);
var statuses = {
0: 'FullyDecrypted',
1: 'FullyEncrypted',
2: 'EncryptionInProgress',
3: 'DecryptionInProgress',
4: 'EncryptionPaused',
5: 'DecryptionPaused'
};
ret[drive].volumeStatus = statuses.hasOwnProperty(values[i].ConversionStatus) ? statuses[values[i].ConversionStatus] : 'FullyDecrypted';
ret[drive].protectionStatus = (values[i].ProtectionStatus == 0 ? 'Off' : (values[i].ProtectionStatus == 1 ? 'On' : 'Unknown'));
try {
var foundIDMarkedLine = false, foundMarkedLine = false, identifier = '', password = '';
var keychild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'manage-bde -protectors -get ' + drive + ': -Type recoverypassword'], {});
keychild.stdout.str = ''; keychild.stdout.on('data', function (c) { this.str += c.toString(); });
keychild.waitExit();
var lines = keychild.stdout.str.trim().split('\r\n');
for (var x = 0; x < lines.length; x++) { // Loop each line
var abc = lines[x].trim();
var englishidpass = (abc !== '' && abc.includes('Numerical Password:')); // English ID
var germanidpass = (abc !== '' && abc.includes('Numerisches Kennwort:')); // German ID
var frenchidpass = (abc !== '' && abc.includes('Mot de passe num')); // French ID
var englishpass = (abc !== '' && abc.includes('Password:') && !abc.includes('Numerical Password:')); // English Password
var germanpass = (abc !== '' && abc.includes('Kennwort:') && !abc.includes('Numerisches Kennwort:')); // German Password
var frenchpass = (abc !== '' && abc.includes('Mot de passe :') && !abc.includes('Mot de passe num')); // French Password
if (englishidpass || germanidpass || frenchidpass|| englishpass || germanpass || frenchpass) {
var nextline = lines[x + 1].trim();
if (x + 1 < lines.length && (nextline !== '' && (nextline.startsWith('ID:') || nextline.startsWith('ID :')) )) {
identifier = nextline.replace('ID:','').replace('ID :', '').trim();
foundIDMarkedLine = true;
}else if (x + 1 < lines.length && nextline !== '') {
password = nextline;
foundMarkedLine = true;
}
}
}
ret[drive].identifier = (foundIDMarkedLine ? identifier : ''); // Set Bitlocker Identifier
ret[drive].recoveryPassword = (foundMarkedLine ? password : ''); // Set Bitlocker Password
} catch(ex) { } // just carry on as we cant get bitlocker key
}
}
p1._res(ret);
} catch (ex) { p1._res(ret); } // just return volumes as cant get encryption/bitlocker
return (p1);
}
module.exports = {
getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } },
volumes_promise: windows_volumes
};

View file

@ -485,8 +485,8 @@ function windows_execve(name, agentfilename, sessionid) {
var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true }); var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true });
var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize); var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize);
var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true }); var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true });
var arg2 = require('_GenericMarshal').CreateVariable('/C net stop "' + name + '" & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' + var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' +
' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & net start "' + name + '" & erase "' + cwd + agentfilename + '.update.exe"', { wide: true }); ' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + cwd + agentfilename + '.update.exe"', { wide: true });
if (name == null) if (name == null)
{ {

View file

@ -152,7 +152,7 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
obj.ProcessData = function (data) { obj.ProcessData = function (data) {
data = Buffer.from(data, 'binary'); data = Buffer.from(data, 'binary');
obj.bytesFromAmt += data.length; obj.bytesFromAmt += data.length;
if (obj.acc == null) { obj.acc = data; } else { obj.acc = Buffer.concat([obj.acc, data]); } if (obj.acc == null) { obj.acc = data; } else { obj.acc = Buffer.concat(obj.acc, data); }
if (obj.debug) console.log('IDER-ProcessData', obj.acc.length, obj.acc.toString('hex')); if (obj.debug) console.log('IDER-ProcessData', obj.acc.length, obj.acc.toString('hex'));
// Process as many commands as possible // Process as many commands as possible

View file

@ -274,7 +274,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected); obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
} else { } else {
// Direct connect with TLS // Direct connect with TLS
var options = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false }; var options = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
if (obj.xtlsMethod != 0) { options.secureProtocol = 'TLSv1_method'; } if (obj.xtlsMethod != 0) { options.secureProtocol = 'TLSv1_method'; }
if (obj.xtlsoptions) { if (obj.xtlsoptions) {
if (obj.xtlsoptions.ca) { options.ca = obj.xtlsoptions.ca; } if (obj.xtlsoptions.ca) { options.ca = obj.xtlsoptions.ca; }

View file

@ -707,15 +707,7 @@ module.exports.CreateAmtManager = function (parent) {
dev.aquired.controlMode = responses['IPS_HostBasedSetupService'].response.CurrentControlMode; // 1 = CCM, 2 = ACM dev.aquired.controlMode = responses['IPS_HostBasedSetupService'].response.CurrentControlMode; // 1 = CCM, 2 = ACM
if (typeof stack.wsman.comm.amtVersion == 'string') { // Set the Intel AMT version using the HTTP header if present if (typeof stack.wsman.comm.amtVersion == 'string') { // Set the Intel AMT version using the HTTP header if present
var verSplit = stack.wsman.comm.amtVersion.split('.'); var verSplit = stack.wsman.comm.amtVersion.split('.');
if (verSplit.length >= 2) { if (verSplit.length >= 3) { dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); }
dev.aquired.version = verSplit[0] + '.' + verSplit[1];
dev.aquired.majorver = parseInt(verSplit[0]);
dev.aquired.minorver = parseInt(verSplit[1]);
if (verSplit.length >= 3) {
dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
dev.aquired.maintenancever = parseInt(verSplit[2]);
}
}
} }
dev.aquired.realm = stack.wsman.comm.digestRealm; dev.aquired.realm = stack.wsman.comm.digestRealm;
dev.aquired.user = dev.intelamt.user = stack.wsman.comm.user; dev.aquired.user = dev.intelamt.user = stack.wsman.comm.user;
@ -758,8 +750,7 @@ module.exports.CreateAmtManager = function (parent) {
// Start power polling if not connected to LMS // Start power polling if not connected to LMS
var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); } var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); }
ppfunc.dev = dev; ppfunc.dev = dev;
if(dev.polltimer){ clearInterval(dev.polltimer); delete dev.polltimer; } dev.polltimer = new setTimeout(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
dev.polltimer = new setInterval(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
fetchPowerState(dev); fetchPowerState(dev);
} else { } else {
// For LMS connections, close now. // For LMS connections, close now.
@ -939,8 +930,8 @@ module.exports.CreateAmtManager = function (parent) {
if (response.Body.OSPowerSavingState == 2) { meshPowerState = 1; } // Fully powered (S0); if (response.Body.OSPowerSavingState == 2) { meshPowerState = 1; } // Fully powered (S0);
else if (response.Body.OSPowerSavingState == 3) { meshPowerState = 2; } // Modern standby (We are going to call this S1); else if (response.Body.OSPowerSavingState == 3) { meshPowerState = 2; } // Modern standby (We are going to call this S1);
// Set OS power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN // Set OS power state
if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); } if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), 4, meshPowerState, null, { name: dev.name }); }
}); });
} else { } else {
// Convert the power state // Convert the power state
@ -949,15 +940,14 @@ module.exports.CreateAmtManager = function (parent) {
var meshPowerState = -1, powerConversionTable = [-1, -1, 1, 2, 3, 6, 6, 5, 6]; var meshPowerState = -1, powerConversionTable = [-1, -1, 1, 2, 3, 6, 6, 5, 6];
if (powerstate < powerConversionTable.length) { meshPowerState = powerConversionTable[powerstate]; } else { powerstate = 6; } if (powerstate < powerConversionTable.length) { meshPowerState = powerConversionTable[powerstate]; } else { powerstate = 6; }
// Set power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN // Set power state
if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); } if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), 4, meshPowerState, null, { name: dev.name }); }
} }
}); });
} }
// Perform a power action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE // Perform a power action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL
function performPowerAction(nodeid, action) { function performPowerAction(nodeid, action) {
console.log('performPowerAction', nodeid, action);
var devices = obj.amtDevices[nodeid]; var devices = obj.amtDevices[nodeid];
if (devices == null) return; if (devices == null) return;
for (var i in devices) { for (var i in devices) {
@ -970,7 +960,7 @@ module.exports.CreateAmtManager = function (parent) {
// Action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset // Action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset
try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { } try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { }
} else { } else {
// 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE // 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL
dev.amtstack.BatchEnum(null, ['*AMT_BootSettingData'], performAdvancedPowerActionResponse); dev.amtstack.BatchEnum(null, ['*AMT_BootSettingData'], performAdvancedPowerActionResponse);
} }
} }
@ -985,44 +975,20 @@ module.exports.CreateAmtManager = function (parent) {
if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response. if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
if (status != 200) return; if (status != 200) return;
if ((responses['AMT_BootSettingData'] == null) || (responses['AMT_BootSettingData'].response == null)) return; if ((responses['AMT_BootSettingData'] == null) || (responses['AMT_BootSettingData'].response == null)) return;
var bootSettingData = responses['AMT_BootSettingData'].response; var bootSettingData = responses['AMT_BootSettingData'].response;
// Clean up parameters
bootSettingData['ConfigurationDataReset'] = false;
delete bootSettingData['WinREBootEnabled'];
delete bootSettingData['UEFILocalPBABootEnabled'];
delete bootSettingData['UEFIHTTPSBootEnabled'];
delete bootSettingData['SecureBootControlEnabled'];
delete bootSettingData['BootguardStatus'];
delete bootSettingData['OptionsCleared'];
delete bootSettingData['BIOSLastStatus'];
delete bootSettingData['UefiBootParametersArray'];
delete bootSettingData['RPEEnabled'];
delete bootSettingData['RSEPassword']
// Ready boot parameters
bootSettingData['BIOSSetup'] = ((action >= 11) && (action <= 14)); bootSettingData['BIOSSetup'] = ((action >= 11) && (action <= 14));
bootSettingData['UseSOL'] = ((action >= 13) && (action <= 14)); bootSettingData['UseSOL'] = ((action >= 13) && (action <= 14));
if ((action == 11) || (action == 13) || (action == 15)) { dev.powerAction = 2; } // Power on if ((action == 11) || (action == 13)) { dev.powerAction = 2; } // Power on
if ((action == 12) || (action == 14) || (action == 16)) { dev.powerAction = 10; } // Reset if ((action == 12) || (action == 14)) { dev.powerAction = 10; } // Reset
// Set boot parameters dev.amtstack.Put('AMT_BootSettingData', bootSettingData, function performAdvancedPowerActionResponseEx(stack, name, response, status, tag) {
dev.amtstack.Put('AMT_BootSettingData', bootSettingData, function (stack, name, response, status, tag) {
const dev = stack.dev; const dev = stack.dev;
if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error const action = dev.powerAction;
// Set boot config delete dev.powerAction;
dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status, tag) { if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
const dev = stack.dev; if (status != 200) return;
if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { }
// Set boot order
var bootDevice = (action === 15 || action === 16) ? '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: Force PXE Boot</Selector></SelectorSet></ReferenceParameters>' : null;
dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(bootDevice, function (stack, name, response, status) {
const dev = stack.dev;
if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
// Perform power action
try { dev.amtstack.RequestPowerStateChange(dev.powerAction, performPowerActionResponse); } catch (ex) { }
}, 0, 1);
}, 0, 1);
}, 0, 1); }, 0, 1);
} }
@ -1069,7 +1035,7 @@ module.exports.CreateAmtManager = function (parent) {
if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); delete dev.ocrfile; return; } if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); delete dev.ocrfile; return; }
// Check if this Intel AMT device supports OCR // Check if this Intel AMT device supports OCR
if (responses['AMT_BootCapabilities'].response['ForceUEFIHTTPSBoot'] !== true) { if (responses['AMT_PublicKeyCertificate'].responses['ForceUEFIHTTPSBoot'] !== true) {
dev.consoleMsg("This Intel AMT device does not support UEFI HTTPS boot (" + status + ")."); delete dev.ocrfile; return; dev.consoleMsg("This Intel AMT device does not support UEFI HTTPS boot (" + status + ")."); delete dev.ocrfile; return;
} }
@ -1099,14 +1065,11 @@ module.exports.CreateAmtManager = function (parent) {
// Generate the one-time URL. // Generate the one-time URL.
var cookie = obj.parent.encodeCookie({ a: 'f', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey) var cookie = obj.parent.encodeCookie({ a: 'f', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey)
var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.efi'; var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.iso';
delete dev.ocrfile; delete dev.ocrfile;
// Generate the boot data for OCR with URL // Generate the boot data for OCR with URL
var r = response.Body; var r = response.Body;
r['BIOSPause'] = false;
r['BIOSSetup'] = false;
r['EnforceSecureBoot'] = false;
r['UefiBootParametersArray'] = Buffer.from(makeUefiBootParam(1, url) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2), 'binary').toString('base64'); r['UefiBootParametersArray'] = Buffer.from(makeUefiBootParam(1, url) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2), 'binary').toString('base64');
r['UefiBootNumberOfParams'] = 3; r['UefiBootNumberOfParams'] = 3;
r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR) r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
@ -1127,7 +1090,8 @@ module.exports.CreateAmtManager = function (parent) {
dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status) { dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status) {
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
if (status != 200) { dev.consoleMsg("Failed to set boot config role (" + status + ")."); return; } if (status != 200) { dev.consoleMsg("Failed to set boot config role (" + status + ")."); return; }
dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder('<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: Force OCR UEFI HTTPS Boot</Selector></SelectorSet></ReferenceParameters>', function (stack, name, response, status) { var bootSource = 'Force OCR UEFI HTTPS Boot';
dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder((bootSource == null) ? bootSource : '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: ' + bootSource + '</Selector></SelectorSet></ReferenceParameters>', function (stack, name, response, status) {
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request. if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
if (status != 200) { dev.consoleMsg("Failed to set boot config (" + status + ")."); return; } if (status != 200) { dev.consoleMsg("Failed to set boot config (" + status + ")."); return; }
dev.amtstack.RequestPowerStateChange(10, function (stack, name, response, status) { // 10 = Reset, 2 = Power Up dev.amtstack.RequestPowerStateChange(10, function (stack, name, response, status) { // 10 = Reset, 2 = Power Up
@ -1330,7 +1294,7 @@ module.exports.CreateAmtManager = function (parent) {
} }
// Figure out what index is local & remote // Figure out what index is local & remote
var localNdx = ((dev.policy != null) && (dev.policy.tlsSettings != null) && (dev.policy.tlsSettings[0] != null) && (dev.policy.tlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx); var localNdx = ((dev.policy.tlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);
// Remote TLS settings // Remote TLS settings
var xxTlsSettings2 = Clone(dev.policy.tlsSettings); var xxTlsSettings2 = Clone(dev.policy.tlsSettings);
@ -2632,14 +2596,7 @@ module.exports.CreateAmtManager = function (parent) {
if (domain && domain.amtmanager && (domain.amtmanager.tlsacmactivation == true)) { TlsAcmActivation = true; } if (domain && domain.amtmanager && (domain.amtmanager.tlsacmactivation == true)) { TlsAcmActivation = true; }
// Check Intel AMT version // Check Intel AMT version
if (typeof dev.intelamt.ver == 'string') { if (typeof dev.intelamt.ver == 'string') { var verSplit = dev.intelamt.ver.split('.'); if (verSplit.length >= 3) { dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); } }
var verSplit = dev.intelamt.ver.split('.');
if (verSplit.length >= 2) {
dev.aquired.majorver = parseInt(verSplit[0]);
dev.aquired.minorver = parseInt(verSplit[1]);
if (verSplit.length >= 3) { dev.aquired.maintenancever = parseInt(verSplit[2]); }
}
}
// If this is Intel AMT 14 or better and allowed, we are going to attempt a host-based end-to-end TLS activation. // If this is Intel AMT 14 or better and allowed, we are going to attempt a host-based end-to-end TLS activation.
if (TlsAcmActivation && (dev.aquired.majorver >= 14)) { if (TlsAcmActivation && (dev.aquired.majorver >= 14)) {
@ -2695,15 +2652,7 @@ module.exports.CreateAmtManager = function (parent) {
dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM
if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') { if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') {
var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.'); var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
if (verSplit.length >= 2) { if (verSplit.length >= 3) { dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); }
dev.aquired.version = verSplit[0] + '.' + verSplit[1];
dev.aquired.majorver = parseInt(verSplit[0]);
dev.aquired.minorver = parseInt(verSplit[1]);
if (verSplit.length >= 3) {
dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
dev.aquired.maintenancever = parseInt(verSplit[2]);
}
}
} }
if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) { if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix; dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
@ -2838,10 +2787,8 @@ module.exports.CreateAmtManager = function (parent) {
var vs = getInstance(amtlogicalelements, 'AMT')['VersionString']; var vs = getInstance(amtlogicalelements, 'AMT')['VersionString'];
if (vs != null) { if (vs != null) {
dev.aquired.version = vs; dev.aquired.version = vs;
version = dev.aquired.version.split('.') dev.aquired.versionmajor = parseInt(dev.aquired.version.split('.')[0]);
dev.aquired.versionmajor = parseInt(version[0]); dev.aquired.versionminor = parseInt(dev.aquired.version.split('.')[1]);
dev.aquired.versionminor = parseInt(version[1]);
if (version.length > 2) { dev.aquired.versionmaintenance = parseInt(version[2]); }
} }
} }
} }
@ -2849,14 +2796,10 @@ module.exports.CreateAmtManager = function (parent) {
// Fetch the Intel AMT version from HTTP stack // Fetch the Intel AMT version from HTTP stack
if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) { if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) {
var s = stack.wsman.comm.amtVersion.split('.'); var s = stack.wsman.comm.amtVersion.split('.');
if (s.length >= 2) { if (s.length >= 3) {
dev.aquired.version = s[0] + '.' + s[1] + '.'; dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
dev.aquired.versionmajor = parseInt(s[0]); dev.aquired.versionmajor = parseInt(s[0]);
dev.aquired.versionminor = parseInt(s[1]); dev.aquired.versionminor = parseInt(s[1]);
if (s.length >= 3) {
dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
dev.aquired.versionmaintenance = parseInt(s[2]);
}
} }
} }

View file

@ -201,10 +201,8 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) {
var vs = getInstance(amtlogicalelements, 'AMT')['VersionString']; var vs = getInstance(amtlogicalelements, 'AMT')['VersionString'];
if (vs != null) { if (vs != null) {
dev.aquired.version = vs; dev.aquired.version = vs;
const versionSplit = parseInt(dev.aquired.version.split('.')); dev.aquired.versionmajor = parseInt(dev.aquired.version.split('.')[0]);
dev.aquired.versionmajor = parseInt(versionSplit[0]); dev.aquired.versionminor = parseInt(dev.aquired.version.split('.')[1]);
dev.aquired.versionminor = parseInt(versionSplit[1]);
if (versionSplit.length >= 3) { dev.aquired.versionmaintenance = parseInt(versionSplit[2]); }
} }
} }
} }
@ -212,14 +210,10 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) {
// Fetch the Intel AMT version from HTTP stack // Fetch the Intel AMT version from HTTP stack
if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) { if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) {
var s = stack.wsman.comm.amtVersion.split('.'); var s = stack.wsman.comm.amtVersion.split('.');
if (s.length >= 2) { if (s.length >= 3) {
dev.aquired.version = s[0] + '.' + s[1]; dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
dev.aquired.versionmajor = parseInt(s[0]); dev.aquired.versionmajor = parseInt(s[0]);
dev.aquired.versionminor = parseInt(s[1]); dev.aquired.versionminor = parseInt(s[1]);
if (s.length >= 3) {
dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
dev.aquired.versionmaintenance = parseInt(s[2]);
}
} }
} }

View file

@ -362,8 +362,8 @@ module.exports.CreateAmtScanner = function (parent) {
if (oldVer == newVer) return false; // Versions are same already, don't update. if (oldVer == newVer) return false; // Versions are same already, don't update.
if (newVer == undefined || newVer == null) return false; // New version is bad, don't update it. if (newVer == undefined || newVer == null) return false; // New version is bad, don't update it.
if (oldVer == undefined || oldVer == null) return true; // Old version is no good anyway, update it. if (oldVer == undefined || oldVer == null) return true; // Old version is no good anyway, update it.
var oldVerArr = oldVer.toString().split('.'); var oldVerArr = oldVer.split('.');
var newVerArr = newVer.toString().split('.'); var newVerArr = newVer.split('.');
if ((oldVerArr.length < 2) || (newVerArr.length < 2)) return false; if ((oldVerArr.length < 2) || (newVerArr.length < 2)) return false;
if ((oldVerArr[0] != newVerArr[0]) || (oldVerArr[1] != newVerArr[1])) return true; if ((oldVerArr[0] != newVerArr[0]) || (oldVerArr[1] != newVerArr[1])) return true;
if (newVerArr.length > oldVerArr.length) return true; if (newVerArr.length > oldVerArr.length) return true;

View file

@ -1,4 +1,4 @@
/** /**
* @description MeshCentral MSTSC & SSH relay * @description MeshCentral MSTSC & SSH relay
* @author Ylian Saint-Hilaire & Bryan Roe * @author Ylian Saint-Hilaire & Bryan Roe
* @copyright Intel Corporation 2018-2022 * @copyright Intel Corporation 2018-2022
@ -35,29 +35,28 @@ const PROTOCOL_WEBSFTP = 203;
const PROTOCOL_WEBVNC = 204; const PROTOCOL_WEBVNC = 204;
// Mesh Rights // Mesh Rights
const MESHRIGHT_EDITMESH = 0x00000001; // 1 const MESHRIGHT_EDITMESH = 0x00000001; // 1
const MESHRIGHT_MANAGEUSERS = 0x00000002; // 2 const MESHRIGHT_MANAGEUSERS = 0x00000002; // 2
const MESHRIGHT_MANAGECOMPUTERS = 0x00000004; // 4 const MESHRIGHT_MANAGECOMPUTERS = 0x00000004; // 4
const MESHRIGHT_REMOTECONTROL = 0x00000008; // 8 const MESHRIGHT_REMOTECONTROL = 0x00000008; // 8
const MESHRIGHT_AGENTCONSOLE = 0x00000010; // 16 const MESHRIGHT_AGENTCONSOLE = 0x00000010; // 16
const MESHRIGHT_SERVERFILES = 0x00000020; // 32 const MESHRIGHT_SERVERFILES = 0x00000020; // 32
const MESHRIGHT_WAKEDEVICE = 0x00000040; // 64 const MESHRIGHT_WAKEDEVICE = 0x00000040; // 64
const MESHRIGHT_SETNOTES = 0x00000080; // 128 const MESHRIGHT_SETNOTES = 0x00000080; // 128
const MESHRIGHT_REMOTEVIEWONLY = 0x00000100; // 256 const MESHRIGHT_REMOTEVIEWONLY = 0x00000100; // 256
const MESHRIGHT_NOTERMINAL = 0x00000200; // 512 const MESHRIGHT_NOTERMINAL = 0x00000200; // 512
const MESHRIGHT_NOFILES = 0x00000400; // 1024 const MESHRIGHT_NOFILES = 0x00000400; // 1024
const MESHRIGHT_NOAMT = 0x00000800; // 2048 const MESHRIGHT_NOAMT = 0x00000800; // 2048
const MESHRIGHT_DESKLIMITEDINPUT = 0x00001000; // 4096 const MESHRIGHT_DESKLIMITEDINPUT = 0x00001000; // 4096
const MESHRIGHT_LIMITEVENTS = 0x00002000; // 8192 const MESHRIGHT_LIMITEVENTS = 0x00002000; // 8192
const MESHRIGHT_CHATNOTIFY = 0x00004000; // 16384 const MESHRIGHT_CHATNOTIFY = 0x00004000; // 16384
const MESHRIGHT_UNINSTALL = 0x00008000; // 32768 const MESHRIGHT_UNINSTALL = 0x00008000; // 32768
const MESHRIGHT_NODESKTOP = 0x00010000; // 65536 const MESHRIGHT_NODESKTOP = 0x00010000; // 65536
const MESHRIGHT_REMOTECOMMAND = 0x00020000; // 131072 const MESHRIGHT_REMOTECOMMAND = 0x00020000; // 131072
const MESHRIGHT_RESETOFF = 0x00040000; // 262144 const MESHRIGHT_RESETOFF = 0x00040000; // 262144
const MESHRIGHT_GUESTSHARING = 0x00080000; // 524288 const MESHRIGHT_GUESTSHARING = 0x00080000; // 524288
const MESHRIGHT_DEVICEDETAILS = 0x00100000; // 1048576 const MESHRIGHT_DEVICEDETAILS = 0x00100000; // 1048576
const MESHRIGHT_RELAY = 0x00200000; // 2097152 const MESHRIGHT_ADMIN = 0xFFFFFFFF;
const MESHRIGHT_ADMIN = 0xFFFFFFFF;
// SerialTunnel object is used to embed TLS within another connection. // SerialTunnel object is used to embed TLS within another connection.
function SerialTunnel(options) { function SerialTunnel(options) {
@ -70,7 +69,7 @@ function SerialTunnel(options) {
} }
// Construct a Web relay object // Construct a Web relay object
module.exports.CreateWebRelaySession = function (parent, db, req, args, domain, userid, nodeid, addr, port, appid, sessionid, expire, mtype) { module.exports.CreateWebRelaySession = function (parent, db, req, args, domain, userid, nodeid, addr, port, appid, sessionid, expire) {
const obj = {}; const obj = {};
obj.parent = parent; obj.parent = parent;
obj.lastOperation = Date.now(); obj.lastOperation = Date.now();
@ -82,7 +81,6 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
obj.appid = appid; obj.appid = appid;
obj.sessionid = sessionid; obj.sessionid = sessionid;
obj.expireTimer = null; obj.expireTimer = null;
obj.mtype = mtype;
var pendingRequests = []; var pendingRequests = [];
var nextTunnelId = 1; var nextTunnelId = 1;
var tunnels = {}; var tunnels = {};
@ -166,7 +164,7 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
// Launch a new tunnel // Launch a new tunnel
if (obj.closed == true) return; if (obj.closed == true) return;
parent.parent.debug('webrelay', 'launchNewTunnel'); parent.parent.debug('webrelay', 'launchNewTunnel');
const tunnel = module.exports.CreateWebRelay(obj, db, args, domain, obj.mtype); const tunnel = module.exports.CreateWebRelay(obj, db, args, domain);
tunnel.onclose = function (tunnelId, processedCount) { tunnel.onclose = function (tunnelId, processedCount) {
if (tunnels == null) return; if (tunnels == null) return;
parent.parent.debug('webrelay', 'tunnel-onclose'); parent.parent.debug('webrelay', 'tunnel-onclose');
@ -240,7 +238,7 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
// Construct a Web relay object // Construct a Web relay object
module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) { module.exports.CreateWebRelay = function (parent, db, args, domain) {
//const Net = require('net'); //const Net = require('net');
const WebSocket = require('ws') const WebSocket = require('ws')
@ -251,7 +249,6 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
obj.isWebSocket = false; // If true, this request will not close and so, it can't be allowed to hold up other requests obj.isWebSocket = false; // If true, this request will not close and so, it can't be allowed to hold up other requests
obj.isStreaming = false; // If true, this request will not close and so, it can't be allowed to hold up other requests obj.isStreaming = false; // If true, this request will not close and so, it can't be allowed to hold up other requests
obj.processedRequestCount = 0; obj.processedRequestCount = 0;
obj.mtype = mtype;
const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead. const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
// Events // Events
@ -263,15 +260,6 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
// Called when we need to close the tunnel because the response stream has closed // Called when we need to close the tunnel because the response stream has closed
function handleResponseClosure() { obj.close(); } function handleResponseClosure() { obj.close(); }
// Return cookie name and values
function parseRequestCookies(cookiesString) {
var r = {};
if (typeof cookiesString != 'string') return r;
var cookieString = cookiesString.split('; ');
for (var i in cookieString) { var j = cookieString[i].indexOf('='); if (j > 0) { r[cookieString[i].substring(0, j)] = cookieString[i].substring(j + 1); } }
return r;
}
// Process a HTTP request // Process a HTTP request
obj.processRequest = function (req, res) { obj.processRequest = function (req, res) {
if (obj.relayActive == false) { console.log("ERROR: Attempt to use an unconnected tunnel"); return false; } if (obj.relayActive == false) { console.log("ERROR: Attempt to use an unconnected tunnel"); return false; }
@ -285,12 +273,10 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
// Construct the HTTP request // Construct the HTTP request
var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n'; var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n';
const blockedHeaders = ['cookie', 'upgrade-insecure-requests', 'sec-ch-ua', 'sec-ch-ua-mobile', 'dnt', 'sec-fetch-user', 'sec-ch-ua-platform', 'sec-fetch-site', 'sec-fetch-mode', 'sec-fetch-dest']; // These are headers we do not forward const blockedHeaders = ['origin', 'cookie', 'upgrade-insecure-requests', 'sec-ch-ua', 'sec-ch-ua-mobile', 'dnt', 'sec-fetch-user', 'sec-ch-ua-platform', 'sec-fetch-site', 'sec-fetch-mode', 'sec-fetch-dest']; // These are headers we do not forward
for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } } for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } }
var cookieStr = ''; var cookieStr = '';
for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); } for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); }
var reqCookies = parseRequestCookies(req.headers.cookie);
for (var i in reqCookies) { if ((i != 'xid') && (i != 'xid.sig')) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + reqCookies[i]); } }
if (cookieStr.length > 0) { request += 'cookie: ' + cookieStr + '\r\n' } // If we have session cookies, set them in the header here if (cookieStr.length > 0) { request += 'cookie: ' + cookieStr + '\r\n' } // If we have session cookies, set them in the header here
request += '\r\n'; request += '\r\n';
@ -334,7 +320,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
// Construct the HTTP request // Construct the HTTP request
var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n'; var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n';
const blockedHeaders = ['cookie', 'sec-websocket-extensions']; // These are headers we do not forward const blockedHeaders = ['origin', 'cookie', 'sec-websocket-extensions']; // These are headers we do not forward
for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } } for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } }
var cookieStr = ''; var cookieStr = '';
for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); } for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); }
@ -440,7 +426,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
obj.relayActive = false; obj.relayActive = false;
}; };
// Start the loopback server // Start the looppback server
obj.connect = function (userid, nodeid, addr, port, appid) { obj.connect = function (userid, nodeid, addr, port, appid) {
if (obj.relayActive || obj.closed) return; if (obj.relayActive || obj.closed) return;
obj.addr = addr; obj.addr = addr;
@ -458,7 +444,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
const protocol = (args.tlsoffload) ? 'ws' : 'wss'; const protocol = (args.tlsoffload) ? 'ws' : 'wss';
var domainadd = ''; var domainadd = '';
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=14&auth=' + cookie; // Protocol 14 is Web-TCP const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=14&auth=' + cookie; // Protocol 14 is Web-TCP
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
parent.parent.parent.debug('relay', 'TCP: Connection websocket to ' + url); parent.parent.parent.debug('relay', 'TCP: Connection websocket to ' + url);
obj.wsClient = new WebSocket(url, options); obj.wsClient = new WebSocket(url, options);
@ -690,9 +676,8 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
// If there is a header, send it // If there is a header, send it
if (header != null) { if (header != null) {
const statusCode = parseInt(header.Directive[1]); obj.res.status(parseInt(header.Directive[1])); // Set the status
if ((!isNaN(statusCode)) && (statusCode > 0) && (statusCode <= 999)) { obj.res.status(statusCode); } // Set the status const blockHeaders = ['Directive', 'sec-websocket-extensions', 'connection', 'transfer-encoding']; // We do not forward these headers
const blockHeaders = ['Directive', 'sec-websocket-extensions', 'connection', 'transfer-encoding', 'last-modified', 'content-security-policy', 'cache-control']; // We do not forward these headers
for (var i in header) { for (var i in header) {
if (i == 'set-cookie') { if (i == 'set-cookie') {
for (var ii in header[i]) { for (var ii in header[i]) {
@ -717,16 +702,14 @@ module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
} }
} }
} }
else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i.trim(), header[i]); } // Set the headers if not blocked else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i, header[i]); } // Set the headers if not blocked
} }
// Dont set any Content-Security-Policy at all because some applications like Node-Red, access external websites from there javascript which would be forbidden by the below CSP obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future
//obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future obj.res.set('Cache-Control', 'no-cache'); // Tell the browser not to cache the responses since since the relay port can be used for many relays
//obj.res.set('Content-Security-Policy', "default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline';"); // Set an "allow all" policy, see if the can restrict this in the future
obj.res.set('Cache-Control', 'no-store'); // Tell the browser not to cache the responses since since the relay port can be used for many relays
} }
// If there is data, send it // If there is data, send it
if (data != null) { try { obj.res.write(data, 'binary'); } catch (ex) { } } if (data != null) { obj.res.write(data, 'binary'); }
// If we are done, close the response // If we are done, close the response
if (done == true) { if (done == true) {
@ -821,7 +804,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
obj.relaySocket = socket; obj.relaySocket = socket;
obj.relaySocket.pause(); obj.relaySocket.pause();
obj.relaySocket.on('data', function (chunk) { // Make sure to handle flow control. obj.relaySocket.on('data', function (chunk) { // Make sure to handle flow control.
if (obj.relayActive == true) { obj.relaySocket.pause(); if (obj.wsClient != null) { obj.wsClient.send(chunk, function () { obj.relaySocket.resume(); }); } } if (obj.relayActive == true) { obj.relaySocket.pause(); obj.wsClient.send(chunk, function () { obj.relaySocket.resume(); }); }
}); });
obj.relaySocket.on('end', function () { obj.close(); }); obj.relaySocket.on('end', function () { obj.close(); });
obj.relaySocket.on('error', function (err) { obj.close(); }); obj.relaySocket.on('error', function (err) { obj.close(); });
@ -843,21 +826,22 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
obj.relaySocket.resume(); obj.relaySocket.resume();
} }
} else { } else {
try { // Forward any ping/pong commands to the browser if (typeof data == 'string') {
var cmd = JSON.parse(data); // Forward any ping/pong commands to the browser
var cmd = null;
try { cmd = JSON.parse(data); } catch (ex) { }
if ((cmd != null) && (cmd.ctrlChannel == '102938')) { if ((cmd != null) && (cmd.ctrlChannel == '102938')) {
if (cmd.type == 'ping') { send(['ping']); } if (cmd.type == 'ping') { send(['ping']); }
else if (cmd.type == 'pong') { send(['pong']); } else if (cmd.type == 'pong') { send(['pong']); }
} }
return; return;
} catch (ex) { // You are not JSON data so just send over relaySocket
obj.wsClient._socket.pause();
try {
obj.relaySocket.write(data, function () {
if (obj.wsClient && obj.wsClient._socket) { try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); } }
});
} catch (ex) { console.log(ex); obj.close(); }
} }
obj.wsClient._socket.pause();
try {
obj.relaySocket.write(data, function () {
if (obj.wsClient && obj.wsClient._socket) { try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); } }
});
} catch (ex) { console.log(ex); obj.close(); }
} }
}); });
obj.wsClient.on('close', function () { parent.parent.debug('relay', 'RDP: Relay websocket closed'); obj.close(); }); obj.wsClient.on('close', function () { parent.parent.debug('relay', 'RDP: Relay websocket closed'); obj.close(); });
@ -984,7 +968,6 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
if ((node == null) || (visible == false) || ((rights & MESHRIGHT_REMOTECONTROL) == 0)) { obj.close(); return; } if ((node == null) || (visible == false) || ((rights & MESHRIGHT_REMOTECONTROL) == 0)) { obj.close(); return; }
if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_REMOTEVIEWONLY) != 0)) { obj.viewonly = true; } if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_REMOTEVIEWONLY) != 0)) { obj.viewonly = true; }
if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_DESKLIMITEDINPUT) != 0)) { obj.limitedinput = true; } if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_DESKLIMITEDINPUT) != 0)) { obj.limitedinput = true; }
node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials
obj.mtype = node.mtype; // Store the device group type obj.mtype = node.mtype; // Store the device group type
obj.meshid = node.meshid; // Store the MeshID obj.meshid = node.meshid; // Store the MeshID
@ -1047,11 +1030,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
if ((k == 14) || (k == 28)) { ok = true; } // Enter and backspace if ((k == 14) || (k == 28)) { ok = true; } // Enter and backspace
if (ok == false) return; if (ok == false) return;
} }
var extended = false; if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventScancode(msg[1], msg[2]); } break;
var extendedkeys = [57419,57421,57416,57424,57426,57427,57417,57425,57372,57397,57415,57423,57373,57400,57399];
// left,right,up,down,insert,delete,pageup,pagedown,numpadenter,numpaddivide,home,end,controlright,altright,printscreen
if (extendedkeys.includes(msg[1])) extended=true;
if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventScancode(msg[1], msg[2], extended); } break;
} }
case 'unicode': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventUnicode(msg[1], msg[2]); } break; } case 'unicode': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventUnicode(msg[1], msg[2]); } break; }
case 'utype': { case 'utype': {
@ -1215,7 +1194,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
const protocol = (args.tlsoffload) ? 'ws' : 'wss'; const protocol = (args.tlsoffload) ? 'ws' : 'wss';
var domainadd = ''; var domainadd = '';
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + obj.xcookie; // Protocol 11 is Web-SSH const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + obj.xcookie; // Protocol 11 is Web-SSH
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
parent.parent.debug('relay', 'SSH: Connection websocket to ' + url); parent.parent.debug('relay', 'SSH: Connection websocket to ' + url);
obj.wsClient = new WebSocket(url, options); obj.wsClient = new WebSocket(url, options);
@ -1282,14 +1261,16 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
ws._socket.resume(); ws._socket.resume();
} }
} else { } else {
try { // Forward any ping/pong commands to the browser if (typeof data == 'string') {
// Forward any ping/pong commands to the browser
var cmd = null; var cmd = null;
cmd = JSON.parse(data); try { cmd = JSON.parse(data); } catch (ex) { }
if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); } if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); }
return; return;
} catch(ex) { // Relay WS --> SSH instead
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
} }
// Relay WS --> SSH
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
} }
}); });
obj.wsClient.on('close', function () { parent.parent.debug('relay', 'SSH: Relay websocket closed'); obj.close(); }); obj.wsClient.on('close', function () { parent.parent.debug('relay', 'SSH: Relay websocket closed'); obj.close(); });
@ -1317,7 +1298,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
// Check if we have SSH credentials for this device // Check if we have SSH credentials for this device
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
if ((err != null) || (nodes == null) || (nodes.length != 1)) return; if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials const node = nodes[0];
if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[obj.userid] == null) || (typeof node.ssh[obj.userid].u != 'string') || ((typeof node.ssh[obj.userid].p != 'string') && (typeof node.ssh[obj.userid].k != 'string'))) { if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[obj.userid] == null) || (typeof node.ssh[obj.userid].u != 'string') || ((typeof node.ssh[obj.userid].p != 'string') && (typeof node.ssh[obj.userid].k != 'string'))) {
// Send a request for SSH authentication // Send a request for SSH authentication
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { } try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
@ -1365,7 +1346,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
obj.termSize = msg; obj.termSize = msg;
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
if ((err != null) || (nodes == null) || (nodes.length != 1)) return; if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials const node = nodes[0];
if (node.ssh != null) { if (node.ssh != null) {
obj.username = node.ssh.u; obj.username = node.ssh.u;
obj.privateKey = node.ssh.k; obj.privateKey = node.ssh.k;
@ -1407,7 +1388,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) { parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
if (obj.cookie == null) return; // obj has been cleaned up, just exit. if (obj.cookie == null) return; // obj has been cleaned up, just exit.
if ((err != null) || (nodes == null) || (nodes.length != 1)) { parent.parent.debug('relay', 'SSH: Invalid device'); obj.close(); } if ((err != null) || (nodes == null) || (nodes.length != 1)) { parent.parent.debug('relay', 'SSH: Invalid device'); obj.close(); }
const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials const node = nodes[0];
obj.nodeid = node._id; // Store the NodeID obj.nodeid = node._id; // Store the NodeID
obj.meshid = node.meshid; // Store the MeshID obj.meshid = node.meshid; // Store the MeshID
obj.mtype = node.mtype; // Store the device group type obj.mtype = node.mtype; // Store the device group type
@ -1552,7 +1533,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
const protocol = (args.tlsoffload) ? 'ws' : 'wss'; const protocol = (args.tlsoffload) ? 'ws' : 'wss';
var domainadd = ''; var domainadd = '';
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + authCookie // Protocol 11 is Web-SSH const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + authCookie // Protocol 11 is Web-SSH
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
parent.parent.debug('relay', 'SSH: Connection websocket to ' + url); parent.parent.debug('relay', 'SSH: Connection websocket to ' + url);
obj.wsClient = new WebSocket(url, options); obj.wsClient = new WebSocket(url, options);
@ -1620,14 +1601,16 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
ws._socket.resume(); ws._socket.resume();
} }
} else { } else {
try { // Forward any ping/pong commands to the browser if (typeof data == 'string') {
// Forward any ping/pong commands to the browser
var cmd = null; var cmd = null;
cmd = JSON.parse(data); try { cmd = JSON.parse(data); } catch (ex) { }
if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { try { obj.ws.send(data); } catch (ex) { console.log(ex); } } if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { try { obj.ws.send(data); } catch (ex) { console.log(ex); } }
return; return;
} catch (ex) { // Relay WS --> SSH
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
} }
// Relay WS --> SSH
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
} }
}); });
obj.wsClient.on('close', function () { obj.wsClient.on('close', function () {
@ -1740,7 +1723,6 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid
parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) { parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) {
if (obj.ws == null) return; // obj has been cleaned up, just exit. if (obj.ws == null) return; // obj has been cleaned up, just exit.
node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials
// Check permissions // Check permissions
if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights
@ -1905,7 +1887,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
const protocol = (args.tlsoffload) ? 'ws' : 'wss'; const protocol = (args.tlsoffload) ? 'ws' : 'wss';
var domainadd = ''; var domainadd = '';
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' } if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=13&auth=' + authCookie // Protocol 13 is Web-SSH-Files const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=13&auth=' + authCookie // Protocol 13 is Web-SSH-Files
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument. if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
parent.parent.debug('relay', 'SSH: Connection websocket to ' + url); parent.parent.debug('relay', 'SSH: Connection websocket to ' + url);
obj.wsClient = new WebSocket(url, options); obj.wsClient = new WebSocket(url, options);
@ -1967,15 +1949,16 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
ws._socket.resume(); ws._socket.resume();
} }
} else { } else {
try { if (typeof data == 'string') {
// Forward any ping/pong commands to the browser // Forward any ping/pong commands to the browser
var cmd = null; var cmd = null;
cmd = JSON.parse(data); try { cmd = JSON.parse(data); } catch (ex) { }
if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); } if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); }
return; return;
} catch (ex) { // Relay WS --> SSH
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
} }
// Relay WS --> SSH
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
} }
}); });
obj.wsClient.on('close', function () { obj.wsClient.on('close', function () {
@ -2270,7 +2253,6 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid
parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) { parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) {
if (obj.ws == null) return; // obj has been cleaned up, just exit. if (obj.ws == null) return; // obj has been cleaned up, just exit.
node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials
// Check permissions // Check permissions
if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights
@ -2335,6 +2317,6 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
function checkRelayRights(parent, domain, user, relayNodeId, func) { function checkRelayRights(parent, domain, user, relayNodeId, func) {
if (relayNodeId == null) { func(true); return; } // No relay, do nothing. if (relayNodeId == null) { func(true); return; } // No relay, do nothing.
parent.GetNodeWithRights(domain, user, relayNodeId, function (node, rights, visible) { parent.GetNodeWithRights(domain, user, relayNodeId, function (node, rights, visible) {
func((node != null) && ((rights & 0x00200008) != 0)); // MESHRIGHT_REMOTECONTROL or MESHRIGHT_RELAY rights func((node != null) && (rights == 0xFFFFFFFF));
}); });
} }

View file

@ -298,7 +298,7 @@ function createAuthenticodeHandler(path) {
for (var i = 0; i < obj.header.coff.numberOfSections; i++) { for (var i = 0; i < obj.header.coff.numberOfSections; i++) {
var section = {}; var section = {};
buf = readFileSlice(obj.header.SectionHeadersPtr + (i * 40), 40); buf = readFileSlice(obj.header.SectionHeadersPtr + (i * 40), 40);
if ((buf[0] != 46) && (buf[0] != 95)) { obj.close(); return false; }; // Name of the section must start with a dot or underscore. If not, something is wrong. if (buf[0] != 46) { obj.close(); return false; }; // Name of the section must start with a dot. If not, something is wrong.
var sectionName = buf.slice(0, 8).toString().trim('\0'); var sectionName = buf.slice(0, 8).toString().trim('\0');
var j = sectionName.indexOf('\0'); var j = sectionName.indexOf('\0');
if (j >= 0) { sectionName = sectionName.substring(0, j); } // Trim any trailing zeroes if (j >= 0) { sectionName = sectionName.substring(0, j); } // Trim any trailing zeroes
@ -1566,11 +1566,7 @@ function createAuthenticodeHandler(path) {
options.protocol = timeServerUrl.protocol; options.protocol = timeServerUrl.protocol;
options.hostname = timeServerUrl.hostname; options.hostname = timeServerUrl.hostname;
options.path = timeServerUrl.pathname; options.path = timeServerUrl.pathname;
let http = require("http") options.port = ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port));
if (options.protocol === "https:"){
http = require("https")
}
options.port = ((timeServerUrl.port == '') ? (options.protocol === "https:" ? 443 : 80) : parseInt(timeServerUrl.port));
if (options.proxy == null) { if (options.proxy == null) {
// No proxy needed // No proxy needed
@ -1588,7 +1584,7 @@ function createAuthenticodeHandler(path) {
// Set up the request // Set up the request
var responseAccumulator = ''; var responseAccumulator = '';
var req = http.request(options, function (res) { var req = require('http').request(options, function (res) {
res.setEncoding('utf8'); res.setEncoding('utf8');
res.on('data', function (chunk) { responseAccumulator += chunk; }); res.on('data', function (chunk) { responseAccumulator += chunk; });
res.on('end', function () { func(null, responseAccumulator); }); res.on('end', function () { func(null, responseAccumulator); });
@ -1609,12 +1605,12 @@ function createAuthenticodeHandler(path) {
proxyOptions.protocol = proxyUrl.protocol; proxyOptions.protocol = proxyUrl.protocol;
proxyOptions.hostname = proxyUrl.hostname; proxyOptions.hostname = proxyUrl.hostname;
proxyOptions.path = options.hostname + ':' + options.port; proxyOptions.path = options.hostname + ':' + options.port;
proxyOptions.port = ((proxyUrl.port == '') ? (options.protocol === "https:" ? 443 : 80) : parseInt(proxyUrl.port)); proxyOptions.port = ((proxyUrl.port == '') ? 80 : parseInt(proxyUrl.port));
} }
// Set up the proxy request // Set up the proxy request
var responseAccumulator = ''; var responseAccumulator = '';
var req = http.request(proxyOptions); var req = require('http').request(proxyOptions);
req.on('error', function (err) { func('' + err); }); req.on('error', function (err) { func('' + err); });
req.on('connect', function (res, socket, head) { req.on('connect', function (res, socket, head) {
// Make a request over the HTTP tunnel // Make a request over the HTTP tunnel

View file

@ -262,10 +262,7 @@ module.exports.CertificateOperations = function (parent) {
acmconfig.cn = certCommonName.value; acmconfig.cn = certCommonName.value;
} }
} }
if(r.certs[0].md){
acmconfig.hashAlgorithm = r.certs[0].md.algorithm;
}
delete acmconfig.cert; delete acmconfig.cert;
delete acmconfig.certpass; delete acmconfig.certpass;
acmconfig.certs = orderedCerts; acmconfig.certs = orderedCerts;
@ -636,16 +633,9 @@ module.exports.CertificateOperations = function (parent) {
}; };
// Return the SHA384 hash of the certificate public key // Return the SHA384 hash of the certificate public key
obj.getPublicKeyHashBinary = function (pem) { obj.getPublicKeyHashBinary = function (cert) {
const { X509Certificate } = require('crypto'); var publickey = obj.pki.certificateFromPem(cert).publicKey;
if (X509Certificate == null) { return obj.pki.getPublicKeyFingerprint(publickey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
return obj.pki.getPublicKeyFingerprint(obj.pki.certificateFromPem(pem).publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
} else {
// This version of NodeJS supports x509 certificates
var cert = new X509Certificate(pem);
return obj.crypto.createHash('sha384').update(cert.publicKey.export({ type: ((cert.publicKey.asymmetricKeyType == 'rsa') ? 'pkcs1' : 'spki'), format: 'der' })).digest('binary');
}
}; };
// Return the SHA384 hash of the certificate, return binary // Return the SHA384 hash of the certificate, return binary
@ -750,7 +740,7 @@ module.exports.CertificateOperations = function (parent) {
} }
// Return true if the name is found in the certificates names, we support wildcard certificates // Return true if the name is found in the certificates names, we support wildcard certificates
obj.compareCertificateNames = function (certNames, name) { obj.compareCertificateNames = function(certNames, name) {
if (certNames == null) return false; if (certNames == null) return false;
name = name.toLowerCase(); name = name.toLowerCase();
var xcertNames = []; var xcertNames = [];
@ -768,102 +758,12 @@ module.exports.CertificateOperations = function (parent) {
// Return true if the certificate is valid // Return true if the certificate is valid
obj.checkCertificate = function (pem, key) { obj.checkCertificate = function (pem, key) {
const { X509Certificate } = require('crypto'); var cert = null;
if (X509Certificate == null) { try { cert = obj.pki.certificateFromPem(pem); } catch (ex) { return false; } // Unable to decode certificate
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs. if (cert.serialNumber == '') return false; // Empty serial number is not allowed.
var cert = null;
try { cert = obj.pki.certificateFromPem(pem); } catch (ex) { return false; } // Unable to decode certificate
if (cert.serialNumber == '') return false; // Empty serial number is not allowed.
} else {
// This version of NodeJS supports x509 certificates
try {
const cert = new X509Certificate(pem);
if ((cert.serialNumber == '') || (cert.serialNumber == null)) return false; // Empty serial number is not allowed.
} catch (ex) { return false; } // Unable to decode certificate
}
return true; return true;
} }
// Get the Common Name from a certificate
obj.getCertificateCommonName = function (pem, field) {
if (field == null) { field = 'CN'; }
const { X509Certificate } = require('crypto');
if (X509Certificate == null) {
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
var cert = obj.pki.certificateFromPem(pem);
if (cert.subject.getField(field) != null) return cert.subject.getField(field).value;
} else {
// This version of NodeJS supports x509 certificates
const subjects = new X509Certificate(pem).subject.split('\n');
for (var i in subjects) { if (subjects[i].startsWith(field + '=')) { return subjects[i].substring(field.length + 1); } }
}
return null;
}
// Get the Issuer Common Name from a certificate
obj.getCertificateIssuerCommonName = function (pem, field) {
if (field == null) { field = 'CN'; }
const { X509Certificate } = require('crypto');
if (X509Certificate == null) {
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
var cert = obj.pki.certificateFromPem(pem);
if (cert.issuer.getField(field) != null) return cert.issuer.getField(field).value;
} else {
// This version of NodeJS supports x509 certificates
const subjects = new X509Certificate(pem).issuer.split('\n');
for (var i in subjects) { if (subjects[i].startsWith(field + '=')) { return subjects[i].substring(field.length + 1); } }
}
return null;
}
// Get the Common Name and alternate names from a certificate
obj.getCertificateAltNames = function (pem) {
const altNamesResults = [];
const { X509Certificate } = require('crypto');
if (X509Certificate == null) {
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
var cert = obj.pki.certificateFromPem(pem);
if (cert.subject.getField('CN') != null) { altNamesResults.push(cert.subject.getField('CN').value); }
var altNames = cert.getExtension('subjectAltName');
if (altNames) {
for (i = 0; i < altNames.altNames.length; i++) {
if ((altNames.altNames[i] != null) && (altNames.altNames[i].type === 2) && (typeof altNames.altNames[i].value === 'string')) {
var acn = altNames.altNames[i].value.toLowerCase();
if (altNamesResults.indexOf(acn) == -1) { altNamesResults.push(acn); }
}
}
}
} else {
// This version of NodeJS supports x509 certificates
const cert = new X509Certificate(pem);
const subjects = cert.subject.split('\n');
for (var i in subjects) { if (subjects[i].startsWith('CN=')) { altNamesResults.push(subjects[i].substring(3)); } }
var subjectAltNames = cert.subjectAltName;
if (subjectAltNames != null) {
subjectAltNames = subjectAltNames.split(', ');
for (var i = 0; i < subjectAltNames.length; i++) {
if (subjectAltNames[i].startsWith('DNS:') && altNamesResults.indexOf(subjectAltNames[i].substring(4)) == -1) {
altNamesResults.push(subjectAltNames[i].substring(4));
}
}
}
}
return altNamesResults;
}
// Get the expiration time from a certificate
obj.getCertificateExpire = function (pem) {
const altNamesResults = [];
const { X509Certificate } = require('crypto');
if (X509Certificate == null) {
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
return Date.parse(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.web.cert).validity.notAfter);
} else {
// This version of NodeJS supports x509 certificates
return Date.parse(new X509Certificate(pem).validTo);
}
}
// Decrypt private key if needed // Decrypt private key if needed
obj.decryptPrivateKey = function (key) { obj.decryptPrivateKey = function (key) {
if (typeof key != 'string') return key; if (typeof key != 'string') return key;
@ -1020,11 +920,22 @@ 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.getCertificateCommonName(r.mps.cert); r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField('CN').value;
r.WebIssuer = obj.getCertificateIssuerCommonName(r.web.cert); var webCertificate = obj.pki.certificateFromPem(r.web.cert);
r.CommonName = obj.getCertificateCommonName(r.web.cert); r.WebIssuer = webCertificate.issuer.getField('CN').value;
r.CommonNames = obj.getCertificateAltNames(r.web.cert); r.CommonName = webCertificate.subject.getField('CN').value;
r.RootName = obj.getCertificateCommonName(r.root.cert); r.CommonNames = [ r.CommonName ];
var altNames = webCertificate.getExtension('subjectAltName');
if (altNames) {
for (i = 0; i < altNames.altNames.length; i++) {
if ((altNames.altNames[i] != null) && (altNames.altNames[i].type === 2) && (typeof altNames.altNames[i].value === 'string')) {
var acn = altNames.altNames[i].value.toLowerCase();
if (r.CommonNames.indexOf(acn) == -1) { r.CommonNames.push(acn); }
}
}
}
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
r.RootName = rootCertificate.subject.getField('CN').value;
// If the "cert" name is not set, try to use the certificate CN instead (ok if the certificate is not wildcard). // 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 (commonName == 'un-configured') {
@ -1049,7 +960,6 @@ module.exports.CertificateOperations = function (parent) {
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.");
rcountmax++;
} }
} 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
@ -1078,8 +988,10 @@ module.exports.CertificateOperations = function (parent) {
// If we have all the certificates we need, stop here. // If we have all the certificates we need, stop here.
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
const xcountry = obj.getCertificateCommonName(r.web.cert, 'C'); var xcountry, xcountryField = webCertificate.subject.getField('C');
const xorganization = obj.getCertificateCommonName(r.web.cert, 'O'); if (xcountryField != null) { xcountry = xcountryField.value; }
var xorganization, xorganizationField = webCertificate.subject.getField('O');
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; }
// Check if we have correct certificates. // Check if we have correct certificates.
@ -1093,7 +1005,6 @@ module.exports.CertificateOperations = function (parent) {
return r; return r;
} }
} }
if (parent.configurationFiles != null) { if (parent.configurationFiles != null) {
console.log("Error: Vault/Database missing some certificates."); console.log("Error: Vault/Database missing some certificates.");
if (r.root == null) { console.log(' Code signing certificate is missing.'); } if (r.root == null) { console.log(' Code signing certificate is missing.'); }
@ -1163,8 +1074,7 @@ module.exports.CertificateOperations = function (parent) {
webPrivateKey = r.web.key; webPrivateKey = r.web.key;
} }
} }
var webIssuer = null; var webIssuer = webCertAndKey.cert.issuer.getField('CN').value;
if (webCertAndKey.cert.issuer.getField('CN') != null) { 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;
@ -1221,7 +1131,7 @@ 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);
if (webCertificate.issuer.getField('CN') != null) { r.WebIssuer = webCertificate.issuer.getField('CN').value; } else { r.WebIssuer = null; } 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; }
@ -1408,15 +1318,20 @@ module.exports.CertificateOperations = function (parent) {
// Perform any general operation // Perform any general operation
obj.acceleratorPerformOperation = function (operation, data, tag, func) { obj.acceleratorPerformOperation = function (operation, data, tag, func) {
var acc = obj.getAccelerator(); if (acceleratorTotalCount <= 1) {
if (acc == null) { // No accelerators available
// Add to pending accelerator workload require(program).processMessage({ action: operation, data: data, tag: tag, func: func });
acceleratorPerformSignaturePushFuncCall++;
pendingAccelerator.push({ action: operation, data: data, tag: tag, func: func });
} else { } else {
// Send to accelerator now var acc = obj.getAccelerator();
acceleratorPerformSignatureRunFuncCall++; if (acc == null) {
acc.send(acc.x = { action: operation, data: data, tag: tag, func: func }); // Add to pending accelerator workload
acceleratorPerformSignaturePushFuncCall++;
pendingAccelerator.push({ action: operation, data: data, tag: tag, func: func });
} else {
// Send to accelerator now
acceleratorPerformSignatureRunFuncCall++;
acc.send(acc.x = { action: operation, data: data, tag: tag, func: func });
}
} }
}; };

View file

@ -142,39 +142,22 @@ module.exports.zeroPad = function(num, c) { if (c == null) { c = 2; } var s = '0
// Lowercase all the names in a object recursively // Lowercase all the names in a object recursively
// Allow for exception keys, child of exceptions will not get lower-cased. // Allow for exception keys, child of exceptions will not get lower-cased.
// Exceptions is an array of "keyname" or "parent\keyname" module.exports.objKeysToLower = function (obj, exceptions) {
module.exports.objKeysToLower = function (obj, exceptions, parent) {
for (var i in obj) { for (var i in obj) {
if ((typeof obj[i] == 'object') && if ((typeof obj[i] == 'object') && ((exceptions == null) || (exceptions.indexOf(i.toLowerCase()) == -1))) { module.exports.objKeysToLower(obj[i], exceptions); } // LowerCase all key names in the child object
((exceptions == null) || (exceptions.indexOf(i.toLowerCase()) == -1) && ((parent == null) || (exceptions.indexOf(parent.toLowerCase() + '/' + i.toLowerCase()) == -1)))
) {
module.exports.objKeysToLower(obj[i], exceptions, i); // LowerCase all key names in the child object
}
if (i.toLowerCase() !== i) { obj[i.toLowerCase()] = obj[i]; delete obj[i]; } // LowerCase all key names if (i.toLowerCase() !== i) { obj[i.toLowerCase()] = obj[i]; delete obj[i]; } // LowerCase all key names
} }
return obj; return obj;
}; };
// Escape and unescape field names so there are no invalid characters for MongoDB/NeDB ("$", ",", ".", see https://github.com/seald/nedb/tree/master?tab=readme-ov-file#inserting-documents) // Escape and unescape feild names so there are no invalid characters for MongoDB
module.exports.escapeFieldName = function (name) { if ((name.indexOf(',') == -1) && (name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24').split(',').join('%2C'); }; module.exports.escapeFieldName = function (name) { if ((name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24'); };
module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2C').join(',').split('%2E').join('.').split('%24').join('$').split('%25').join('%'); }; module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
// Escape all links, SSH and RDP usernames // Escape all links
// This is required for databases like NeDB that don't accept "." or "," as part of a field name. module.exports.escapeLinksFieldNameEx = function (docx) { if (docx.links == null) { return docx; } var doc = Object.assign({}, docx); doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } return doc; };
module.exports.escapeLinksFieldNameEx = function (docx) { if ((docx.links == null) && (docx.ssh == null) && (docx.rdp == null)) { return docx; } return module.exports.escapeLinksFieldName(docx); }; module.exports.escapeLinksFieldName = function (docx) { var doc = Object.assign({}, docx); if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } } return doc; };
module.exports.escapeLinksFieldName = function (docx) { module.exports.unEscapeLinksFieldName = function (doc) { if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; };
var doc = Object.assign({}, docx);
if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } }
if (doc.ssh != null) { doc.ssh = Object.assign({}, doc.ssh); for (var i in doc.ssh) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.ssh[ue] = doc.ssh[i]; delete doc.ssh[i]; } } }
if (doc.rdp != null) { doc.rdp = Object.assign({}, doc.rdp); for (var i in doc.rdp) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.rdp[ue] = doc.rdp[i]; delete doc.rdp[i]; } } }
return doc;
};
module.exports.unEscapeLinksFieldName = function (doc) {
if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } }
if (doc.ssh != null) { for (var j in doc.ssh) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.ssh[ue] = doc.ssh[j]; delete doc.ssh[j]; } } }
if (doc.rdp != null) { for (var j in doc.rdp) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.rdp[ue] = doc.rdp[j]; delete doc.rdp[j]; } } }
return doc;
};
//module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } return docs; }; //module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } return docs; };
module.exports.unEscapeAllLinksFieldName = function (docs) { for (var i in docs) { docs[i] = module.exports.unEscapeLinksFieldName(docs[i]); } return docs; }; module.exports.unEscapeAllLinksFieldName = function (docs) { for (var i in docs) { docs[i] = module.exports.unEscapeLinksFieldName(docs[i]); } return docs; };
@ -334,11 +317,6 @@ module.exports.meshServerRightsArrayToNumber = function (val) {
if (r == 'locked') { newAccRights |= 32; } if (r == 'locked') { newAccRights |= 32; }
if (r == 'nonewgroups') { newAccRights |= 64; } if (r == 'nonewgroups') { newAccRights |= 64; }
if (r == 'notools') { newAccRights |= 128; } if (r == 'notools') { newAccRights |= 128; }
if (r == 'usergroups') { newAccRights |= 256; }
if (r == 'recordings') { newAccRights |= 512; }
if (r == 'locksettings') { newAccRights |= 1024; }
if (r == 'allevents') { newAccRights |= 2048; }
if (r == 'nonewdevices') { newAccRights |= 4096; }
} }
return newAccRights; return newAccRights;
} }
@ -391,32 +369,4 @@ module.exports.moveOldFiles = function (filelist) {
for (var i in filelist) { if (fs.existsSync(filelist[i] + oldFileExt) == true) { extOk = false; } } for (var i in filelist) { if (fs.existsSync(filelist[i] + oldFileExt) == true) { extOk = false; } }
} while (extOk == false); } while (extOk == false);
for (var i in filelist) { try { fs.renameSync(filelist[i], filelist[i] + oldFileExt); } catch (ex) { } } for (var i in filelist) { try { fs.renameSync(filelist[i], filelist[i] + oldFileExt); } catch (ex) { } }
}
// Convert strArray to Array, returns array if strArray or null if any other type
module.exports.convertStrArray = function (object, split) {
if (split && typeof object === 'string') {
return object.split(split)
} else if (typeof object === 'string') {
return Array(object);
} else if (Array.isArray(object)) {
return object
} else {
return []
}
}
module.exports.uniqueArray = function (a) {
var seen = {};
var out = [];
var len = a.length;
var j = 0;
for(var i = 0; i < len; i++) {
var item = a[i];
if(seen[item] !== 1) {
seen[item] = 1;
out[j++] = item;
}
}
return out;
} }

2197
db.js

File diff suppressed because it is too large Load diff

View file

@ -1,16 +1,15 @@
"@seald-io/nedb": "4.0.4", "archiver": "^5.3.1",
"archiver": "7.0.1", "body-parser": "^1.19.0",
"body-parser": "1.20.3", "cbor": "~5.2.0",
"cbor": "5.2.0", "compression": "^1.7.4",
"compression": "1.7.5", "cookie-session": "^1.4.0",
"cookie-session": "2.1.0", "express": "^4.17.0",
"express": "4.21.2", "express-handlebars": "^5.3.5",
"express-handlebars": "7.1.3", "express-ws": "^4.0.0",
"express-ws": "5.0.2", "ipcheck": "^0.1.0",
"ipcheck": "0.1.0", "minimist": "^1.2.5",
"minimist": "1.2.8", "multiparty": "^4.2.1",
"multiparty": "4.2.3", "@yetzt/nedb": "^1.8.0",
"node-forge": "1.3.1", "node-forge": "^1.0.0",
"ua-parser-js": "1.0.39", "ws": "^5.2.3",
"ws": "8.18.0", "yauzl": "^2.10.0"
"yauzl": "2.10.0"

View file

@ -1,24 +1,35 @@
FROM --platform=$BUILDPLATFORM node:22-alpine AS builder FROM alpine:latest AS base
#Add non-root user, add installation directories and assign proper permissions
RUN mkdir -p /opt/meshcentral/meshcentral RUN mkdir -p /opt/meshcentral/meshcentral
COPY ./ /opt/meshcentral/meshcentral/
# meshcentral installation
WORKDIR /opt/meshcentral WORKDIR /opt/meshcentral
RUN apk update \
&& apk add --no-cache --update tzdata nodejs npm bash \
&& rm -rf /var/cache/apk/*
RUN npm install -g npm@latest
FROM base AS builder
ARG DISABLE_MINIFY="" ARG DISABLE_MINIFY=""
ARG DISABLE_TRANSLATE="" ARG DISABLE_TRANSLATE=""
COPY ./ /opt/meshcentral/meshcentral/
RUN if ! [ -z "$DISABLE_MINIFY" ] && [ "$DISABLE_MINIFY" != "yes" ] && [ "$DISABLE_MINIFY" != "YES" ] \ RUN if ! [ -z "$DISABLE_MINIFY" ] && [ "$DISABLE_MINIFY" != "yes" ] && [ "$DISABLE_MINIFY" != "YES" ] \
&& [ "$DISABLE_MINIFY" != "true" ] && [ "$DISABLE_MINIFY" != "TRUE" ]; then \ && [ "$DISABLE_MINIFY" != "true" ] && [ "$DISABLE_MINIFY" != "TRUE" ]; then \
echo -e "\e[0;31;49mInvalid value for build argument DISABLE_MINIFY, possible values: yes/true\e[;0m"; exit 1; \ echo -e "\e[0;31;49mInvalid value for build argument DISABLE_MINIFY, possible values: yes/true\e[;0m"; exit 1; \
fi fi
RUN if ! [ -z "$DISABLE_TRANSLATE" ] && [ "$DISABLE_TRANSLATE" != "yes" ] && [ "$DISABLE_TRANSLATE" != "YES" ] \ RUN if ! [ -z "$DISABLE_TRANSLATE" ] && [ "$DISABLE_TRANSLATE" != "yes" ] && [ "$DISABLE_TRANSLATE" != "YES" ] \
&& [ "$DISABLE_TRANSLATE" != "true" ] && [ "$DISABLE_TRANSLATE" != "TRUE" ]; then \ && [ "$DISABLE_TRANSLATE" != "true" ] && [ "$DISABLE_TRANSLATE" != "TRUE" ]; then \
echo -e "\e[0;31;49mInvalid value for build argument DISABLE_TRANSLATE, possible values: yes/true\e[;0m"; exit 1; \ echo -e "\e[0;31;49mInvalid value for build argument DISABLE_TRANSLATE, possible values: yes/true\e[;0m"; exit 1; \
fi fi
# install translate/minify modules if need too # install translate/minify modules if need too
RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral && npm install html-minifier@4.0.0 jsdom@22.1.0 esprima@4.0.1; fi RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral && npm install html-minifier jsdom minify-js; fi
# first extractall if need too # first extractall if need too
RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral/translate && node translate.js extractall; fi RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral/translate && node translate.js extractall; fi
@ -34,18 +45,7 @@ RUN rm -rf /opt/meshcentral/meshcentral/docker
RUN rm -rf /opt/meshcentral/meshcentral/node_modules RUN rm -rf /opt/meshcentral/meshcentral/node_modules
FROM --platform=$TARGETPLATFORM alpine:3.21 FROM base
#Add non-root user, add installation directories and assign proper permissions
RUN mkdir -p /opt/meshcentral/meshcentral
# meshcentral installation
WORKDIR /opt/meshcentral
RUN apk update \
&& apk add --no-cache --update tzdata nodejs npm bash python3 make gcc g++ \
&& rm -rf /var/cache/apk/*
RUN npm install -g npm@latest
ARG INCLUDE_MONGODBTOOLS="" ARG INCLUDE_MONGODBTOOLS=""
ARG PREINSTALL_LIBS="false" ARG PREINSTALL_LIBS="false"
@ -58,22 +58,20 @@ ENV CONFIG_FILE="config.json"
ENV USE_MONGODB="false" ENV USE_MONGODB="false"
ENV MONGO_INITDB_ROOT_USERNAME="root" ENV MONGO_INITDB_ROOT_USERNAME="root"
ENV MONGO_INITDB_ROOT_PASSWORD="pass" ENV MONGO_INITDB_ROOT_PASSWORD="pass"
ENV MONGO_URL=""
ENV HOSTNAME="localhost" ENV HOSTNAME="localhost"
ENV ALLOW_NEW_ACCOUNTS="true" ENV ALLOW_NEW_ACCOUNTS="true"
ENV ALLOWPLUGINS="false" ENV ALLOWPLUGINS="false"
ENV LOCALSESSIONRECORDING="true" ENV LOCALSESSIONRECORDING="false"
ENV MINIFY="false" ENV MINIFY="true"
ENV WEBRTC="false" ENV WEBRTC="false"
ENV IFRAME="false" ENV IFRAME="false"
ENV SESSION_KEY="" ENV SESSION_KEY=""
ENV REVERSE_PROXY="false" ENV REVERSE_PROXY="false"
ENV REVERSE_PROXY_TLS_PORT="" ENV REVERSE_PROXY_TLS_PORT=""
ENV ARGS=""
RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ] && [ "$INCLUDE_MONGODBTOOLS" != "yes" ] && [ "$INCLUDE_MONGODBTOOLS" != "YES" ] \ RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ] && [ "$INCLUDE_MONGODBTOOLS" != "yes" ] && [ "$INCLUDE_MONGODBTOOLS" != "YES" ] \
&& [ "$INCLUDE_MONGODBTOOLS" != "true" ] && [ "$INCLUDE_MONGODBTOOLS" != "TRUE" ]; then \ && [ "$INCLUDE_MONGODBTOOLS" != "true" ] && [ "$INCLUDE_MONGODBTOOLS" != "TRUE" ]; then \
echo -e "\e[0;31;49mInvalid value for build argument INCLUDE_MONGODBTOOLS, possible values: yes/true\e[;0m"; exit 1; \ echo -e "\e[0;31;49mInvalid value for build argument INCLUDE_MONGODBTOOLS, possible values: yes/true\e[;0m"; exit 1; \
fi fi
RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then apk add --no-cache mongodb-tools; fi RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then apk add --no-cache mongodb-tools; fi
@ -83,12 +81,11 @@ COPY --from=builder /opt/meshcentral/meshcentral /opt/meshcentral/meshcentral
COPY ./docker/startup.sh ./startup.sh COPY ./docker/startup.sh ./startup.sh
COPY ./docker/config.json.template /opt/meshcentral/config.json.template COPY ./docker/config.json.template /opt/meshcentral/config.json.template
# install dependencies from package.json # install dependencies from package.json and nedb
RUN cd meshcentral && npm install RUN cd meshcentral && npm install && npm install nedb
# NOTE: ALL MODULES MUST HAVE A VERSION NUMBER AND THE VERSION MUST MATCH THAT USED IN meshcentral.js mainStart() RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then cd meshcentral && npm install mongodb@4.1.0; fi
RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then cd meshcentral && npm install mongodb@4.13.0 saslprep@1.0.3; fi RUN if ! [ -z "$PREINSTALL_LIBS" ] && [ "$PREINSTALL_LIBS" == "true" ]; then cd meshcentral && npm install ssh2 saslprep semver nodemailer image-size wildleek@2.0.0 otplib@10.2.3; fi
RUN if ! [ -z "$PREINSTALL_LIBS" ] && [ "$PREINSTALL_LIBS" == "true" ]; then cd meshcentral && npm install ssh2@1.16.0 semver@7.5.4 nodemailer@6.9.15 image-size@1.1.1 wildleek@2.0.0 otplib@10.2.3 yubikeyotp@0.2.0; fi
EXPOSE 80 443 4433 EXPOSE 80 443 4433
@ -96,6 +93,6 @@ EXPOSE 80 443 4433
VOLUME /opt/meshcentral/meshcentral-data VOLUME /opt/meshcentral/meshcentral-data
VOLUME /opt/meshcentral/meshcentral-files VOLUME /opt/meshcentral/meshcentral-files
VOLUME /opt/meshcentral/meshcentral-web VOLUME /opt/meshcentral/meshcentral-web
VOLUME /opt/meshcentral/meshcentral-backups VOLUME /opt/meshcentral/meshcentral-backup
CMD ["bash", "/opt/meshcentral/startup.sh"] CMD ["bash", "/opt/meshcentral/startup.sh"]

View file

@ -1,5 +1,5 @@
{ {
"$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json", "$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
"settings": { "settings": {
"plugins":{"enabled": false}, "plugins":{"enabled": false},
"_mongoDb": null, "_mongoDb": null,
@ -21,9 +21,9 @@
"": { "": {
"_title": "MyServer", "_title": "MyServer",
"_title2": "Servername", "_title2": "Servername",
"minify": false, "minify": true,
"NewAccounts": true, "NewAccounts": true,
"localSessionRecording": true, "localSessionRecording": false,
"_userNameIsEmail": true, "_userNameIsEmail": true,
"_certUrl": "my.reverse.proxy" "_certUrl": "my.reverse.proxy"
} }

View file

@ -10,18 +10,12 @@
| - docker-compose.yml | - docker-compose.yml
``` ```
# Templates # Templates:
## .env:
## .env
You can place the `config.json` file directly under `./meshcentral/data/`, or use the following `.env` file instead.
```ini ```ini
NODE_ENV=production NODE_ENV=production
USE_MONGODB=false # initial mongodb-variables
# set already exist mongo connection string url here
MONGO_URL=
# or set following init params for new mongodb, use it with docker-compose file with mongodb version
MONGO_INITDB_ROOT_USERNAME=mongodbadmin MONGO_INITDB_ROOT_USERNAME=mongodbadmin
MONGO_INITDB_ROOT_PASSWORD=mongodbpasswd MONGO_INITDB_ROOT_PASSWORD=mongodbpasswd
@ -30,7 +24,8 @@ MONGO_INITDB_ROOT_PASSWORD=mongodbpasswd
# your hostname # your hostname
HOSTNAME=my.domain.com HOSTNAME=my.domain.com
# set to your reverse proxy IP if you want to put meshcentral behind a reverse proxy USE_MONGODB=false
# set to your reverse proxy IP if you want to put meshcentral behind a reverse proxy
REVERSE_PROXY=false REVERSE_PROXY=false
REVERSE_PROXY_TLS_PORT= REVERSE_PROXY_TLS_PORT=
# set to true if you wish to enable iframe support # set to true if you wish to enable iframe support
@ -45,12 +40,9 @@ ALLOWPLUGINS=false
LOCALSESSIONRECORDING=false LOCALSESSIONRECORDING=false
# set to enable or disable minification of json, reduces traffic # set to enable or disable minification of json, reduces traffic
MINIFY=true MINIFY=true
# set this value to add extra arguments to meshcentral on startup (e.g --debug ldap)
ARGS=
``` ```
## docker-compose.yml ## docker-compose.yml:
```yaml ```yaml
version: '3' version: '3'
@ -71,13 +63,12 @@ services:
# where file uploads for users live # where file uploads for users live
- ./meshcentral/user_files:/opt/meshcentral/meshcentral-files - ./meshcentral/user_files:/opt/meshcentral/meshcentral-files
# location for the meshcentral-backups - this should be mounted to an external storage # location for the meshcentral-backups - this should be mounted to an external storage
- ./meshcentral/backup:/opt/meshcentral/meshcentral-backups - ./meshcentral/backup:/opt/meshcentral/meshcentral-backup
# location for site customization files # location for site customization files
- ./meshcentral/web:/opt/meshcentral/meshcentral-web - ./meshcentral/web:/opt/meshcentral/meshcentral-web
``` ```
## docker-compose.yml mongodb ## docker-compose.yml mongodb:
```yaml ```yaml
version: '3' version: '3'
@ -116,7 +107,7 @@ services:
# where file uploads for users live # where file uploads for users live
- ./meshcentral/user_files:/opt/meshcentral/meshcentral-files - ./meshcentral/user_files:/opt/meshcentral/meshcentral-files
# location for the meshcentral-backups - this should be mounted to an external storage # location for the meshcentral-backups - this should be mounted to an external storage
- ./meshcentral/backup:/opt/meshcentral/meshcentral-backups - ./meshcentral/backup:/opt/meshcentral/meshcentral-backup
# location for site customization files # location for site customization files
- ./meshcentral/web:/opt/meshcentral/meshcentral-web - ./meshcentral/web:/opt/meshcentral/meshcentral-web
networks: networks:

View file

@ -1,34 +1,28 @@
#!/bin/bash #!/bin/bash
if [ -f "meshcentral-data/${CONFIG_FILE}" ]; then if [ -f "meshcentral-data/${CONFIG_FILE}" ]
node meshcentral/meshcentral --configfile "${CONFIG_FILE}" ${ARGS} then
else node meshcentral/meshcentral --configfile ${CONFIG_FILE}
cp config.json.template meshcentral-data/"${CONFIG_FILE}" else
if [ -n "$USE_MONGODB" ] && [ "$USE_MONGODB" == "true" ]; then cp config.json.template meshcentral-data/${CONFIG_FILE}
if [ -z "$MONGO_URL" ]; then if ! [ -z "$USE_MONGODB" ] && [ "$USE_MONGODB" == "true" ]; then
prefix="" sed -i "s/\"_mongoDb\": null/\"mongoDb\": \"mongodb:\/\/$MONGO_INITDB_ROOT_USERNAME:$MONGO_INITDB_ROOT_PASSWORD@mongodb:27017\"/" meshcentral-data/${CONFIG_FILE}
if [ -n "$MONGO_INITDB_ROOT_USERNAME" ] && [ -n "$MONGO_INITDB_ROOT_PASSWORD" ]; then
prefix="$MONGO_INITDB_ROOT_USERNAME:$MONGO_INITDB_ROOT_PASSWORD@"
fi
MONGO_URL="${prefix}mongodb:27017"
fi fi
sed -i "s/\"_mongoDb\": null/\"mongoDb\": \"mongodb:\/\/$MONGO_URL\"/" meshcentral-data/"${CONFIG_FILE}" sed -i "s/\"cert\": \"myserver.mydomain.com\"/\"cert\": \"$HOSTNAME\"/" meshcentral-data/${CONFIG_FILE}
fi sed -i "s/\"NewAccounts\": true/\"NewAccounts\": $ALLOW_NEW_ACCOUNTS/" meshcentral-data/${CONFIG_FILE}
sed -i "s/\"cert\": \"myserver.mydomain.com\"/\"cert\": \"$HOSTNAME\"/" meshcentral-data/"${CONFIG_FILE}" sed -i "s/\"enabled\": false/\"enabled\": $ALLOWPLUGINS/" meshcentral-data/${CONFIG_FILE}
sed -i "s/\"NewAccounts\": true/\"NewAccounts\": $ALLOW_NEW_ACCOUNTS/" meshcentral-data/"${CONFIG_FILE}" sed -i "s/\"localSessionRecording\": false/\"localSessionRecording\": $LOCALSESSIONRECORDING/" meshcentral-data/${CONFIG_FILE}
sed -i "s/\"enabled\": false/\"enabled\": $ALLOWPLUGINS/" meshcentral-data/"${CONFIG_FILE}" sed -i "s/\"minify\": true/\"minify\": $MINIFY/" meshcentral-data/${CONFIG_FILE}
sed -i "s/\"localSessionRecording\": false/\"localSessionRecording\": $LOCALSESSIONRECORDING/" meshcentral-data/"${CONFIG_FILE}" sed -i "s/\"WebRTC\": false/\"WebRTC\": $WEBRTC/" meshcentral-data/${CONFIG_FILE}
sed -i "s/\"minify\": false/\"minify\": $MINIFY/" meshcentral-data/"${CONFIG_FILE}" sed -i "s/\"AllowFraming\": false/\"AllowFraming\": $IFRAME/" meshcentral-data/${CONFIG_FILE}
sed -i "s/\"WebRTC\": false/\"WebRTC\": $WEBRTC/" meshcentral-data/"${CONFIG_FILE}" if [ -z "$SESSION_KEY" ]; then
sed -i "s/\"AllowFraming\": false/\"AllowFraming\": $IFRAME/" meshcentral-data/"${CONFIG_FILE}" SESSION_KEY="$(cat /dev/urandom | tr -dc 'A-Za-z0-9!#$%&()*+,-./:;<=>?@[\]^_`{|}~' | fold -w 32 | head -n 1)";
if [ -z "$SESSION_KEY" ]; then fi
SESSION_KEY="$(cat /dev/urandom | tr -dc 'A-Z0-9' | fold -w 48 | head -n 1)" sed -i "s/\"_sessionKey\": \"MyReallySecretPassword1\"/\"sessionKey\": \"$SESSION_KEY\"/" meshcentral-data/${CONFIG_FILE}
fi if [ "$REVERSE_PROXY" != "false" ]; then
sed -i "s/\"_sessionKey\": \"MyReallySecretPassword1\"/\"sessionKey\": \"$SESSION_KEY\"/" meshcentral-data/"${CONFIG_FILE}" sed -i "s/\"_certUrl\": \"my\.reverse\.proxy\"/\"certUrl\": \"https:\/\/$REVERSE_PROXY:$REVERSE_PROXY_TLS_PORT\"/" meshcentral-data/${CONFIG_FILE}
if [ "$REVERSE_PROXY" != "false" ]; then node meshcentral/meshcentral --configfile ${CONFIG_FILE}
sed -i "s/\"_certUrl\": \"my\.reverse\.proxy\"/\"certUrl\": \"https:\/\/$REVERSE_PROXY:$REVERSE_PROXY_TLS_PORT\"/" meshcentral-data/"${CONFIG_FILE}" exit
node meshcentral/meshcentral --configfile "${CONFIG_FILE}" ${ARGS} fi
exit node meshcentral/meshcentral --configfile ${CONFIG_FILE} --cert "$HOSTNAME"
fi
node meshcentral/meshcentral --configfile "${CONFIG_FILE}" --cert "$HOSTNAME" ${ARGS}
fi fi

View file

@ -20,17 +20,6 @@ backend sni-back
use-server gitlabSNI if gitlab-sni use-server gitlabSNI if gitlab-sni
use-server mc-SNI if mc-sni use-server mc-SNI if mc-sni
server mc-SNI 10.1.1.10:1443 send-proxy-v2-ssl-cn server mc-SNI 10.1.1.10:1443 send-proxy-v2-ssl-cn
frontend cira-tcp-front
bind 10.1.1.10:4433
mode tcp
option tcplog
tcp-request inspect-delay 5s
default_backend mc-cira-back
backend cira-tcp-back
mode tcp
server mc-cira 10.1.1.30:4433
frontend mc-front-HTTPS frontend mc-front-HTTPS
mode http mode http

View file

@ -2,7 +2,7 @@
![](images/2022-05-15-12-57-36.png) ![](images/2022-05-15-12-57-36.png)
Design and Architecture Guide [as .pdf](https://meshcentral.com/docs/MeshCentral2DesignArchitecture.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral Design & Architecture v0.0.4.odt?raw=true) Design and Architecture Guide [as .pdf](https://meshcentral.com/info/docs/MeshCentral2DesignArchitecture.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral Design & Architecture v0.0.4.odt?raw=true)
## Video Walkthru ## Video Walkthru
<div class="video-wrapper"> <div class="video-wrapper">
@ -108,46 +108,29 @@ Someone would think the server is rather simple when taking a look at the MeshCe
### Code files ### Code files
``` ```
amtevents.js | Used to decode Intel AMT WSMAN events. amtevents.js | Used to scan a local network for Intel AMT machines.
amtmanager.js | Used to handle Intel AMT/CIRA things. amtscanner.js | Used to run Intel AMT scripts from MeshCommander.
amtprovisioningserver.js | Used to Provision Intel AMT on a Local Network. amtscript.js | Used to generate and perform certificate operations.
amtscanner.js | Used to scan a local network for Intel AMT machines. certoperations.js | Various commonly used methods.
amtscript.js | Used to run Intel AMT scripts from MeshCommander. common.js | Used to access the MongoDB or NeDB database.
certoperations.js | Used to generate and perform certificate operations. db.js | Used to modify windows executables.
common.js | Various commonly used methods. exeHandler.js | Used to insert credentials in an HTTP stream.
crowdsec.js | Used to handle all crowdsec security features interceptor.js | Used to obtain and use a Lets Encrypt certificate.
db.js | Used to access the MongoDB or NeDB database. letsencrypt.js | Used to offload RSA sign to other CPU cores.
exeHandler.js | Used to modify windows executables. meshaccelerator.js | Used to communicate to agents.
firebase.js | Used to handle Google Firebase things. meshagent.js | The is the main module, gets the server started.
interceptor.js | Used to insert credentials in an HTTP stream. meshcentral.js | Used to send SMTP mails.
letsencrypt.js | Used to obtain and use a Lets Encrypt certificate. meshmail.js | Used to relay agent and browser web socket connections.
mcrec.js | Standalone Session Recording Indexer. meshrelay.js | MeshCentral server discovery when in LAN mode.
meshaccelerator.js | Used to offload RSA sign to other CPU cores. meshscanner.js | Used to communicate with browsers.
meshagent.js | Used to communicate to agents. meshuser.js | Used to communicate to Intel® AMT CIRA.
meshbot.js | Sample bot to connect to meshcentral and preform various tasks mpsserver.js | Used for server-to-server communication.
meshcentral.js | The is the main module, gets the server started. multiserver.js | Performs password hash + salt.
meshctrl.js | MeshCtrl performs command line actions on a MeshCentral server. pass.js | Used to handle HTTP traffic.
meshcore.js | Main Agent Code that runs on your remote devices. redirserver.js | Used to upgrade legacy MeshCentralv1 agents.
meshdesktopmultiplex.js | Used to handle remote desktop multiplexing. swarmserver.js | Handles HTTPS traffic.
meshdevicefile.js | Used to handle file download requests. webserver.js | Server background install on Windows.
meshipkvm.js | Used to handle IP KVM integration winservice.js | Server background install on Windows.
meshmail.js | Used to send SMTP mails.
meshmessaging.js | Used to handle all users messaging methods like 2FA.
meshrelay.js | Used to relay agent and browser web socket connections.
meshscanner.js | MeshCentral server discovery when in LAN mode.
meshsms.js | Used to handle all users sms methods.
meshuser.js | Used to communicate with browsers.
mpsserver.js | Used to communicate to Intel® AMT CIRA.
mqttbroker.js | Used to create/handle an MQTT broker (beta)
multiserver.js | Used for server-to-server communication.
pass.js | Performs password hash + salt.
redirserver.js | Used to handle HTTP traffic.
swarmserver.js | Used to upgrade legacy MeshCentralv1 agents.
webauthn.js | Handles all WebAuthN things.
webrelayserver.js | Used for all HTTP/HTTPS web relaying from agents.
webserver.js | Handles HTTPS traffic.
winservice.js | Server background install on Windows.
``` ```
At a high level, the MeshCentral.js file will get the server started. By default, it will start the webserver.js on port 443, redirectserver.js on port 80 and mpssrver.js on port 4433. The webserver.js file will create a meshuser.js or meshagent.js instance each time a user or agent connects. The other files support various usages, but this is the basic working on the server. At a high level, the MeshCentral.js file will get the server started. By default, it will start the webserver.js on port 443, redirectserver.js on port 80 and mpssrver.js on port 4433. The webserver.js file will create a meshuser.js or meshagent.js instance each time a user or agent connects. The other files support various usages, but this is the basic working on the server.

27
docs/docs/faq.md Normal file
View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1,56 +0,0 @@
# Contribute to MeshCentral
## Contributing to MeshCentral via GitHub Pull Request
If you're looking to contribute beyond translations, such as updating documentation or enhancing the software by adding features or fixing bugs, the process involves several key steps:
1. **Fork the Repository:** Start by forking the [MeshCentral](https://github.com/Ylianst/MeshCentral) repository on GitHub. This creates a copy of the repository under your own GitHub account, allowing you to make changes without affecting the original project.
2. **Make Your Changes**
- In your forked repository, create a new branch to keep your changes organized. This helps in managing different contributions separately.
- Make the necessary changes in your repository. This could involve updating documentation files or modifying code to add new features or fix bugs.
3. **Review Your Changes:** Before submitting your work, carefully review the changes youve made. Check the "Files Changed" section on GitHub to ensure that all modifications are intended and correctly implemented.
4. **Submit a Pull Request**
- Once your changes are ready and reviewed, submit a pull request (PR) from your branch to the `master` branch of the main MeshCentral repository.
- When creating the pull request, provide a clear and detailed description of what changes have been made and why. This helps maintainers understand the purpose of your contributions.
5. **Wait for Review:** After submitting your pull request, wait for a project maintainer to review your contribution. Review time can vary depending on the complexity of the changes and the availability of the maintainers.
6. **Respond to Feedback:** The maintainer may request further modifications or provide feedback on your pull request. Be prepared to make additional changes based on their suggestions to ensure that your contribution meets the projects standards and requirements.
7. **Final Steps:** Once your pull request is approved and merged by a maintainer, your contributions will be incorporated into the MeshCentral project. Congratulations, and thank you for helping improve MeshCentral!
---
## Contribute to MeshCentral's Multilingual Support
To make MeshCentral multilingual, your contributions are crucial. Follow these steps to translate the interface into various languages.
1. **Remove Local Translations:** Delete `translate.json` from your `meshcentral-data` folder. This file contains your local copy of translations, which may become outdated as new features and texts are added.
2. **Access MeshCentral:** Ensure you are logged into MeshCentral.
3. **Open Translation Tool:** Visit `https://YOURMESHCENTRALSERVER.COM/translator.htm` to access the translation interface.
4. **Choose a Language:** Select the language you wish to translate from the list provided.
5. **Translate Text:** Use the search function or scroll through the list to find text segments you want to translate. Utilize the "show no translations only" checkbox to filter untranslated texts.
6. **Enter Translations:** For each text segment, enter your translation in the bottom box (not the top one) and click `SET (F1)`.
7. **Repeat Translation:** Continue translating by repeating steps 5 and 6 for other texts as desired.
8. **Save and Apply Translations**
- Click `SAVE TO SERVER (F3)` to save your translations to `meshcentral-data/translate.json` locally in your MeshCentral server.
- Optionally, click `SAVE TO FILE (F4)` to download the `translate.json` file for offline review or sharing.
9. **Deploy Translations:** Click `TRANSLATE SERVER` and allow some time for the process to complete (approximately 5-15 minutes depending on server specifications). This command line output will indicate when the translation is complete.
![](images/translation-msg-output.png)
10. **Finalize Changes:** Its crucial to restart MeshCentral to ensure that the translated files are picked up correctly.
11. **Share your translations:** Once a language translation is complete, take the latest `translation.json` and share it by emailing it to the maintainer (Ylianst, `ylianst@gmail.com`) or by submitting it to the MeshCentral GitHub repository via a pull request.
---
#### Additional Information:
- If you make any changes to `default.handlebars`, run the translate server to propagate these modifications to the language-specific handlebar files located in `node_modules/meshcentral/views/translations`.
By following these steps, you help MeshCentral support any language you choose, making it more accessible worldwide. By sharing your translations with us, you also help make these languages available to other users, improving the community and extending the software's reach.

View file

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Before After
Before After

View file

@ -4,6 +4,8 @@
MeshCentral is a full computer management web site. With MeshCentral, you can run your own web server to remotely manage and control computers on a local network or anywhere on the internet. Once you get the server started, create device group and download and install an agent on each computer you want to manage. A minute later, the new computer will show up on the web site and you can take control of it. MeshCentral includes full web-based remote desktop, terminal and file management capability. MeshCentral is a full computer management web site. With MeshCentral, you can run your own web server to remotely manage and control computers on a local network or anywhere on the internet. Once you get the server started, create device group and download and install an agent on each computer you want to manage. A minute later, the new computer will show up on the web site and you can take control of it. MeshCentral includes full web-based remote desktop, terminal and file management capability.
To try out this software on the public server, please visit [MeshCentral.com/login](https://meshcentral.com/login). Be mindful that the public MeshCentral server comes with no guaranties, most should setup their own server.
For more information, [visit MeshCentral.com](https://www.meshcentral.com/). For more information, [visit MeshCentral.com](https://www.meshcentral.com/).
## Social Media ## Social Media
@ -12,17 +14,17 @@ For more information, [visit MeshCentral.com](https://www.meshcentral.com/).
[Reddit](https://www.reddit.com/r/MeshCentral/) [Reddit](https://www.reddit.com/r/MeshCentral/)
[BlueSky](https://bsky.app/profile/meshcentral.bsky.social) [Twitter](https://twitter.com/MeshCentral)
[BlogSpot](https://meshcentral2.blogspot.com/) [BlogSpot](https://meshcentral2.blogspot.com/)
## Documentation ## Documentation
The [User's Guide](meshcentral) contains information every administrator should know including usage, the server configuration file, databases, TLS offloading, Lets Encrypt, IP Filtering, Email setup, embedding, server port aliasing, reverse proxy setup, multi factor authentication, branding & terms of use, HashiCorp Vault support, and SSO. The [User's Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2UserGuide.pdf) contains information every adminstrator should know including usage, the server configuration file, databases, TLS offloading, Lets Encrypt, IP Filtering, Email setup, embedding, server port aliasing, reverse proxy setup, multi factor authentication, branding & terms of use, HashiCorp Vault support, and SSO.
The [Installation Guide](install/install2.md) has detailed instructions for installing the MeshCentral Server on Windows 8.1, Windows 10, Windows 2012 R2, Amazon Linux 2, Raspberry Pi, Microsoft Azure, Google Cloud, Ubuntu 18, Ubuntu 16 and OpenBSD. The [Installation Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2InstallGuide.pdf) has detailed instructions for installing the MeshCentral Server on Windows 8.1, Windows 10, Windows 2012 R2, Amazon Linux 2, Raspberry Pi, Microsoft Azure, Google Cloud, Ubuntu 18, Ubuntu 16 and OpenBSD.
The [Design and Architecture Guide](design) is a short document that includes information on the design overview, dependencies, source code descriptions of each file, certificates, TLS security, the agent to server handshake, browser to agent relay and WebRTC and the messenger service. The [Design and Architecture Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2DesignArchitecture.pdf) is a short document that includes information on the design overview, dependencies, source code descriptions of each file, certificates, TLS security, the agent to server handshake, browser to agent relay and WebRTC and the messenger service.
## Video Tutorials ## Video Tutorials

View file

@ -9,11 +9,11 @@ npm install meshcentral
node node_modules/meshcentral node node_modules/meshcentral
``` ```
That's it. MeshCentral will set itself up and start managing computers on your local network. By default it will be setup in LAN mode and agents you install will multicast on the local network to find the server. To setup the server so that agents use a well known DNS name and to start customizing your server, go in the "meshcentral-data" folder and edit the config.json file. The configuration file must be valid JSON, you can use this [link](https://duckduckgo.com/?va=j&t=hc&q=json+lint&ia=answer) to validate the file format. That's it. MeshCentral will set itself up and start managing computers on your local network. By default it will be setup in LAN mode and agents you install will multicast on the local network to find the server. To setup the server so that agents use a well known DNS name and to start customizing your server, go in the "meshcentral-data" folder and edit the config.json file. The configuration file must be valid JSON, you can use this link to validate the file format.
For Windows users, you can download the MeshCentral Installer that will automate installation of NodeJS and provide basic configuration of the server. This option is not recommended for advanced users. For Windows users, you can download the MeshCentral Installer that will automate installation of NodeJS and provide basic configuration of the server. This option is not recommended for advanced users.
[Win32 MeshCentral Installer](https://meshcentral.com/tools/MeshCentralInstaller.exe) [Win32 MeshCentral Installer](https://meshcentral.com/info/tools/MeshCentralInstaller.exe)
By default, MeshCentral will use NeDB as this is the built-in database. For more advanced users, it's recommended to switch to using MongoDB. MeshCentral can be installed on a very small server. A [Raspberry Pi](https://www.raspberrypi.org/) or [AWS t3.nano running Amazon Linux 2 instance](https://aws.amazon.com/ec2/pricing/on-demand/) for 5$ a month will do just fine for managing up to a few hundred devices. By default, MeshCentral will use NeDB as this is the built-in database. For more advanced users, it's recommended to switch to using MongoDB. MeshCentral can be installed on a very small server. A [Raspberry Pi](https://www.raspberrypi.org/) or [AWS t3.nano running Amazon Linux 2 instance](https://aws.amazon.com/ec2/pricing/on-demand/) for 5$ a month will do just fine for managing up to a few hundred devices.
@ -23,10 +23,10 @@ You can run the MeshCentral Server with --help to get options for background ins
Once you get MeshCentral installed, the first user account that is created will be the server administrator. So, don't delay and navigate to the login page and create a new account. You can then start using your server right away. A lot of the fun with MeshCentral is the 100's of configuration options that are available in the config.json file. You can put your own branding on the web pages, setup a SMTP email server, SMS services and much more. Once you get MeshCentral installed, the first user account that is created will be the server administrator. So, don't delay and navigate to the login page and create a new account. You can then start using your server right away. A lot of the fun with MeshCentral is the 100's of configuration options that are available in the config.json file. You can put your own branding on the web pages, setup a SMTP email server, SMS services and much more.
You can look [here for simple config.json](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config.json), [here for a more advanced configuration](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config-advanced.json) and [here for all possible configuration options](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json). You can also take a look at the [tutorial videos](https://www.youtube.com/@MeshCentral/videos) for additional help. You can look [here for simple config.json](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config.json), [here for a more advanced configuration](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config-advanced.json) and [here for all possible configuration options](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json). You can also take a look at the [MeshCentral User's Guide](https://meshcentral.com/info/docs/MeshCentral2InstallGuide.pdf) and [tutorial videos](https://meshcentral.com/info/tutorials.html) for additional help.
## Video Walkthru ## Video Walkthru
<div class="video-wrapper"> <div class="video-wrapper">
<iframe width="320" height="180" src="https://www.youtube.com/embed/LSiWuu71k_U" frameborder="0" allowfullscreen></iframe> <iframe width="320" height="180" src="https://www.youtube.com/embed/LSiWuu71k_U" frameborder="0" allowfullscreen></iframe>
</div> </div>

View file

@ -4,45 +4,6 @@
This guide is specifically intended to help users install MeshCentral from start to finish. Once installed, you can take a look at the MeshCentral users guide for information on how to configure MeshCentral for your specific use. In this document, we will look at installing MeshCentral on AWS Linux, Raspberry Pi and Ubuntu. This guide is specifically intended to help users install MeshCentral from start to finish. Once installed, you can take a look at the MeshCentral users guide for information on how to configure MeshCentral for your specific use. In this document, we will look at installing MeshCentral on AWS Linux, Raspberry Pi and Ubuntu.
## Docker
<https://github.com/Ylianst/MeshCentral/pkgs/container/meshcentral>
```
docker pull ghcr.io/ylianst/meshcentral:master
```
!!!warning
Do not use the built in mesh update function. Update docker the docker way.
### Docker Compose
```
version: '3'
services:
meshcentral:
restart: unless-stopped # always restart the container unless you stop it
image: ghcr.io/ylianst/meshcentral:1.1.27 # 1.1.27 is a version number OR use master for the master branch of bug fixes
ports:
- 80:80 # HTTP
- 443:443 # HTTPS
- 4433:4433 # AMT (Optional)
volumes:
- data:/opt/meshcentral/meshcentral-data # config.json and other important files live here
- user_files:/opt/meshcentral/meshcentral-files # where file uploads for users live
- backup:/opt/meshcentral/meshcentral-backups # location for the meshcentral backups - this should be mounted to an external storage
- web:/opt/meshcentral/meshcentral-web # location for site customization files
volumes:
data:
driver: local
user_files:
driver: local
backup:
driver: local
web:
driver: local
```
## Quick Start ## Quick Start
For some who want to skip this document entirely, there are quick install scripts that will get a MeshCentral2 instance up and running on Linux in a few minutes. These scripts will pretty much do what this document explains very rapidly. Right now, there are two such scripts available: For some who want to skip this document entirely, there are quick install scripts that will get a MeshCentral2 instance up and running on Linux in a few minutes. These scripts will pretty much do what this document explains very rapidly. Right now, there are two such scripts available:
@ -52,7 +13,7 @@ For some who want to skip this document entirely, there are quick install script
For Amazon EC2 users, that want to manage 100 devices or less. Launch a t3.nano or t3.micro EC2 instance with Amazon Linux 2 with TCP ports 22 (SSH), 80 (HTTP), 443 (HTTPS) and 4433 (CIRA) open. Then login as `ec2-user` and enter the following commands: For Amazon EC2 users, that want to manage 100 devices or less. Launch a t3.nano or t3.micro EC2 instance with Amazon Linux 2 with TCP ports 22 (SSH), 80 (HTTP), 443 (HTTPS) and 4433 (CIRA) open. Then login as `ec2-user` and enter the following commands:
``` ```
wget https://meshcentral.com/scripts/mc-aws-linux2.sh wget http://info.meshcentral.com/scripts/mc-aws-linux2.sh
chmod 755 mc-aws-linux2.sh chmod 755 mc-aws-linux2.sh
./mc-aws-linux2.sh ./mc-aws-linux2.sh
``` ```
@ -60,7 +21,7 @@ chmod 755 mc-aws-linux2.sh
This will download the fast install script and once run, will install nodejs, meshcentral, setup systemd and start the server. For a larger instance like a t3.small, t3.medium or larger you can run the following that does the same but also installs MongoDB. This will download the fast install script and once run, will install nodejs, meshcentral, setup systemd and start the server. For a larger instance like a t3.small, t3.medium or larger you can run the following that does the same but also installs MongoDB.
``` ```
wget https://meshcentral.com/scripts/mc-aws-linux2-mongo.sh wget http://info.meshcentral.com/scripts/mc-aws-linux2-mongo.sh
chmod 755 mc-aws-linux2-mongo.sh chmod 755 mc-aws-linux2-mongo.sh
./mc-aws-linux2-mongo.sh ./mc-aws-linux2-mongo.sh
``` ```
@ -72,19 +33,13 @@ After these scripts are run, try accessing the server using a browser. MeshCentr
For 100 devices or less, launch an instance of Ubuntu 18.04 using a small B1s instance. Set the username to `default` in all lower case and open ports 22, 80, 443 and 3389 using the basic network profile. Then start the instance and run the following lines. For 100 devices or less, launch an instance of Ubuntu 18.04 using a small B1s instance. Set the username to `default` in all lower case and open ports 22, 80, 443 and 3389 using the basic network profile. Then start the instance and run the following lines.
``` ```
wget https://meshcentral.com/scripts/mc-azure-ubuntu1804.sh wget http://info.meshcentral.com/scripts/mc-azure-ubuntu1804.sh
chmod 755 mc-azure-ubuntu1804.sh chmod 755 mc-azure-ubuntu1804.sh
./mc-azure-ubuntu1804.sh ./mc-azure-ubuntu1804.sh
``` ```
In this situation, port 3389 will be used to receive Intel AMT CIRA connections instead of port 4433. After these scripts are run, try accessing the server using a browser. MeshCentral will take a minute or two to create certificates after that, the server will be up. The first account to be created will be the site administrator so dont delay and create an account right away. Once running, move on to the MeshCentrals users guide to configure your new server. In this situation, port 3389 will be used to receive Intel AMT CIRA connections instead of port 4433. After these scripts are run, try accessing the server using a browser. MeshCentral will take a minute or two to create certificates after that, the server will be up. The first account to be created will be the site administrator so dont delay and create an account right away. Once running, move on to the MeshCentrals users guide to configure your new server.
### Elestio
You can deploy MeshCentral on Elestio using one-click deployment. Elestio handles version updates, maintenance, securtiy, backups, etc. Additionally, Elestio supports MeshCentral by providing revenue share so go ahead and click below to deploy and start using.
[![Deploy on Elestio](https://elest.io/images/logos/deploy-to-elestio-btn.png)](https://elest.io/open-source/meshcentral)
## Server Security - Adding Crowdsec ## Server Security - Adding Crowdsec
MeshCentral has built-in support for a CrowdSec bouncer. This allows MeshCentral to get threat signals from the community and block or CAPTCHA requests coming from known bad IP addresses. MeshCentral has built-in support for a CrowdSec bouncer. This allows MeshCentral to get threat signals from the community and block or CAPTCHA requests coming from known bad IP addresses.
@ -929,7 +884,7 @@ The last line will run MeshCentral manually and allow it to install any missing
``` ```
sudo chown -R meshcentral:meshcentral /opt/meshcentral sudo chown -R meshcentral:meshcentral /opt/meshcentral
sudo chmod -R 755 /opt/meshcentral/meshcentral-* sudo chmod 755 R /opt/meshcentral/meshcentral-*
``` ```
To make this work, you will need to make MeshCentral work with MongoDB because the /meshcentral-data folder will be read-only. In addition, MeshCentral will not be able to update itself since the account does not have write access to the /node_modules files, so the update will have to be manual. First used systemctl to stop the MeshCentral server process, than use this: To make this work, you will need to make MeshCentral work with MongoDB because the /meshcentral-data folder will be read-only. In addition, MeshCentral will not be able to update itself since the account does not have write access to the /node_modules files, so the update will have to be manual. First used systemctl to stop the MeshCentral server process, than use this:
@ -946,7 +901,7 @@ This will perform the update to the latest server on NPM and re-set the permissi
MeshCentral allows users to upload and download files stores in the servers `meshcentral-files` folder. In an increased security setup, we still want the server to be able to read and write files to this folder and we can allow this with: MeshCentral allows users to upload and download files stores in the servers `meshcentral-files` folder. In an increased security setup, we still want the server to be able to read and write files to this folder and we can allow this with:
``` ```
sudo chmod -R 755 /opt/meshcentral/meshcentral-files sudo chmod 755 R /opt/meshcentral/meshcentral-files
``` ```
If you plan on using the increased security installation along with MeshCentral built-in Lets Encrypt support you will need to type the following commands to make the `letsencrypt` folder in `meshcentral-data` writable. If you plan on using the increased security installation along with MeshCentral built-in Lets Encrypt support you will need to type the following commands to make the `letsencrypt` folder in `meshcentral-data` writable.
@ -954,19 +909,11 @@ If you plan on using the increased security installation along with MeshCentral
``` ```
sudo mkdir /opt/meshcentral/meshcentral-data sudo mkdir /opt/meshcentral/meshcentral-data
sudo mkdir /opt/meshcentral/meshcentral-data/letsencrypt sudo mkdir /opt/meshcentral/meshcentral-data/letsencrypt
sudo chmod -R 755 /opt/meshcentral/meshcentral-data/letsencrypt sudo chmod 755 R /opt/meshcentral/meshcentral-data/letsencrypt
``` ```
This will allow the server to get and periodically update its Lets Encrypt certificate. If this is not done, the server will generate an `ACCES: permission denied` exception. This will allow the server to get and periodically update its Lets Encrypt certificate. If this is not done, the server will generate an `ACCES: permission denied` exception.
### Restore backup in Ubuntu
- Stop Meshcentral service `sudo systemctl stop meshcentral.service`
- In your old server, get your backup : meshcentral-data folder, and mongodump-xxxx.archive
- In the new server, replace the actual meshcentral-data with your backup (it will handle your LestEncrypt cert also)
- Restore mongodb : mongorestore --archive=mongodump-xxxx.archive
- Restart meshcentral.service `sudo systemctl start meshcentral.service`
## Microsoft Azure ## Microsoft Azure
In this section, we will look installing MeshCentral on Microsoft Azure. Microsoft Azure offers many operating system options and we will be selecting `Ubuntu Server` as our choice. From the Azure portal, we select `Virtual machines` on the left and `Add`. In this section, we will look installing MeshCentral on Microsoft Azure. Microsoft Azure offers many operating system options and we will be selecting `Ubuntu Server` as our choice. From the Azure portal, we select `Virtual machines` on the left and `Add`.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

View file

@ -49,16 +49,6 @@ Intel® AMT
If you are looking into managing remote computers that would be difficult to physically get access to for remote support or maintenance, one should probably look at getting a PC with Intel AMT. If you are looking into managing remote computers that would be difficult to physically get access to for remote support or maintenance, one should probably look at getting a PC with Intel AMT.
## Bare-Metal Activation Server
The `AmtProvisioningServer` section in the `settings` section of the config.json will enable this feature. MeshCentral will then listen for activation requests, match against your ACM activation certificates and if everything goes well, will activate and add the device to a Intel AMT only device group. No agent or MeshCMD is involved.
This bare-metal activation server is not enabled by default and only makes sense when activating devices on the local network.
Once enabled, Intel AMT can send “hello” data to the MeshCentral provisioning server on port 9971 and MeshCentral will respond by connecting back, authenticating, and activating Intel AMT. MeshCentral will then log the event, add the device to a pre-defined agent-less device group and complete any remaining configuration. A trusted CA certificate is required to perform this operation fully automatically.
![baremetal](images/amtprovisioningserver.png)
## MeshCentral Group Types ## MeshCentral Group Types
Once MeshCentral is installed, a user will typically create a new device group. Here is the first hint that MeshCentral supports Intel AMT. Device groups come in two types. You can manage using a software agent, or using Intel AMT only. Once MeshCentral is installed, a user will typically create a new device group. Here is the first hint that MeshCentral supports Intel AMT. Device groups come in two types. You can manage using a software agent, or using Intel AMT only.
@ -185,22 +175,12 @@ Once setup, Intel AMT will not automatically activate to Intel AMT unless the ri
- The name “meshcentral.com” by have been set as “Trusted FQDN” in MEBx. - The name “meshcentral.com” by have been set as “Trusted FQDN” in MEBx.
- The name “meshcentral.com” must have been set using a USB key with a setup.bin file. - The name “meshcentral.com” must have been set using a USB key with a setup.bin file.
<div class="video-wrapper">
<iframe width="320" height="180" src="https://www.youtube.com/embed/mhq0bsWJEOw" frameborder="0" allowfullscreen></iframe>
</div>
Once Intel AMT is in a situation where ACM activation can occur, the activation command line can be run or the Mesh Agent will detect this situation and ask the server to perform activation. Once Intel AMT is in a situation where ACM activation can occur, the activation command line can be run or the Mesh Agent will detect this situation and ask the server to perform activation.
![](images/2022-05-16-23-16-05.png) ![](images/2022-05-16-23-16-05.png)
The best way to test this feature is to create an “Intel AMT only” device group and run the MeshCMD command on the remote system to perform activation. If there is a problem, this process should clearly display why ACM activation fails. The best way to test this feature is to create an “Intel AMT only” device group and run the MeshCMD command on the remote system to perform activation. If there is a problem, this process should clearly display why ACM activation fails.
!!!note
Activation over wifi has some additional issues.<br>
First you need to add your WiFi access point to that wifi configuration to allow CSME to take over WiFi when OS is not functioning. Then it should work.<br>
Please also make sure you install Intel WiFi driver and Intel LMS package. It should work. You can detach the ethernet and then try connecting to that device using the IP address acquired by WiFi interface.
See [Open AMT Cloud Toolkit](https://www.intel.com/content/www/us/en/developer/topic-technology/edge-5g/tools/open-amt-cloud-toolkit.html) project - a close relative to this project. It has an AMT activation component and newer remote provisioning client can activate locally and also can manage Wi-Fi profile.
## Intel AMT MEI and LMS ## Intel AMT MEI and LMS
Intel Active Management Technology (Intel AMT) can communicate to the local platform using the Management Engine Interface (MEI). We show how your can use that to get Intel AMT information. For more advanced usages, you need to connect using TCP and TLS which requires Intel Local Manageability Service (LMS). We show how MeshCentral's Mesh Agent and MeshCMD have a small version of LMS built-in and how it works Intel Active Management Technology (Intel AMT) can communicate to the local platform using the Management Engine Interface (MEI). We show how your can use that to get Intel AMT information. For more advanced usages, you need to connect using TCP and TLS which requires Intel Local Manageability Service (LMS). We show how MeshCentral's Mesh Agent and MeshCMD have a small version of LMS built-in and how it works

View file

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

View file

@ -25,8 +25,6 @@ xxx Path: `c:\Program Files\Mesh Agent\meshagent.msh`
## Linux / BSD ## Linux / BSD
Uninstall: `sudo /usr/local/mesh_services/meshagent/[agent-name]/meshagent -fulluninstall`
## Apple macOS Binary Installer ## Apple macOS Binary Installer
Default Install Path: `/usr/local/mesh_services/meshagent/meshagent` Default Install Path: `/usr/local/mesh_services/meshagent/meshagent`
@ -40,17 +38,13 @@ launchctl stop meshagent
launchctl start meshagent launchctl start meshagent
``` ```
Install:
Uninstall: `sudo /usr/local/mesh_services/meshagent/[agent-name]/meshagent -fulluninstall`
## Apple macOS Universal ## Apple macOS Universal
For OSx 11+ including Big Sur, Monterey and later For OSx 11+ including Big Sur, Monterey and later
## Apple macOS ## Apple macOS
For macOS 10.x including Catalina, Mojave, High Sierra, Sierra, El Capitan, Yosemite, Mavericks, Mountain Lion and earlier. For macOS 10.x including Catalina, Mojave, High Sierra, Sierra, El Capitan, Yosemite, Mavericks, Mountain Lion and earlier
## Mobile Device (Android) ## Mobile Device (Android)
@ -59,304 +53,3 @@ For macOS 10.x including Catalina, Mojave, High Sierra, Sierra, El Capitan, Yose
See [Assistant](assistant.md) See [Assistant](assistant.md)
## Apple MacOS Binary Installer ## Apple MacOS Binary Installer
## Agent Commands
**agentmsg**
: Add/Remove badged messages to the device's web ui
```
agentmsg add "[message]" [iconIndex]
agentmsg remove [index]
agentmsg list
```
**agentsize**
: Returns the binary size of the agent
**agentupdate**
: Manually trigger an agent self-update
**alert**
: Display an alert dialog on the logged in session
```
alert TITLE, CAPTION [, TIMEOUT]
```
**amt**
**amtconfig**
**amtevents**
**apf**
**args**
**av**
: Displays Antivirus State
**coredump**
**coreinfo**
**cpuinfo**
**cs**
: Display Windows Connected Standby State
**dbcompact**
: Compacts the agent database
**dbget**
**dbkeys**
**dbset**
**dnsinfo**
: Display DNS server info
**domain**
: Display domain metadata
**errorlog**
**eval**
: executes javascript on the agent
```
eval [code]
```
**fdcount**
: Returns the number of active descriptors in the event loop
**fdsnapshot**
: Returns detailed descriptor/handle/timer metadata
**getclip**
: Fetches clipboard data from agent
**getscript**
**help**
: Returns the list of supported console commands
**httpget**
**info**
: Returns general information about the agent, such as connected state, loaded modules, LMS state, etc
**kill**
: Sends a SIGKILL signal to the specified PID
```
kill [pid]
```
**kvmmode**
: Displays the KVM Message Format
**location**
: Displays saves location information about the connected agent
**lock**
**log**
: Writes a message to the logfile
```
log [message]
```
**ls**
: Enumerates the files in the agent's install folder
**mousetrails**
: Enables/Disables Mouse Trails Accessibility on Windows. To change setting, specify a positive integer representing the number of latent cursors, where 0 is disable
```
mousetrails [n]
```
**msh**
: Displays the loaded msh settings file
**netinfo**
: Displays network interface information
**notify**
: Display a notification on the web interface
**openurl**
**osinfo**
: Displays OS information
**parseuri**
: Parses the specified URI, and displays the parsed output
```
parseuri [uri]
```
**plugin**
: Invokes a plugin
```
plugin [pluginName] [args]
```
**power**
: Performs the specified power action
```
power [action]
LOGOFF = 1
SHUTDOWN = 2
REBOOT = 3
SLEEP = 4
HIBERNATE = 5
DISPLAYON = 6
KEEPAWAKE = 7
BEEP = 8
CTRLALTDEL = 9
VIBRATE = 13
FLASH = 14
```
**print**
**privacybar**
: Sets/Gets the default pinned state of the Privacy Bar on windows
```
privacybar [PINNED|UNPINNED]
```
**ps**
: Enumerates processes on the agent
**rawsmbios**
: Fetches the raw smbios table
**safemode**
: Sets/Gets the SAFEMODE configuration of the agent, as well as the next boot state.
```
safemode (ON|OFF|STATUS)
```
**scanwifi**
: Scans the available Wifi access points, and displays the SSID and Signal Strength
**service**
: Shortcut to be able to restart the agent service
```
service status|restart
```
**setclip**
: Sets clipboard data to the agent
```
setclip [text]
```
**setdebug**
: Sets the location target for debug messages
```
setdebug [target]
0 = Disabled
1 = StdOut
2 = This Console
* = All Consoles
4 = WebLog
8 = Logfile
```
**smbios**
: Displays the parsed SMBIOS metadata
**startupoptions**
: Displays the command-line options that the agent was started with
**sysinfo**
: Collects and displays telemetry on the platform
**task**
**taskbar**
: Hides or shows the Windows System task bar, optionally on the specified Terminal Server Session ID
```
taskbar HIDE|SHOW [TSID]
```
**timerinfo**
: Displays metadata about any configured timers on the event loop
**toast**
: Displays a toast message on the logged in user's session
```
toast [message]
```
**translations**
: Shows the currently configured translations
**type**
```
type (filepath) [maxlength]
```
**uac**
: Get/Sets the Windows UAC mode
```
uac [get|interactive|secure]
```
**unzip**
```
unzip input, destination
```
: Unzips the specified file
**users**
: Enumerates the logged in users on the system
**versions**
: Displays version information about the agent
**vm**
: Detects if the system is a Virtual Machine
**volumes**
: Displays volume information reported by the OS
**wakeonlan**
: Sends wake-on-lan packets to the specified MAC address
```
wakeonlan [mac]
```
**wallpaper**
: Gets/Toggles the logged in user's desktop background image
```
wallpaper (GET|TOGGLE)
```
**wpfhwacceleration**
: Enable/Disable WPF HW Acceleration on Windows
```
wpfhwacceleration (ON|OFF|STATUS)
```
**wsclose**
**wsconnect**
**wslist**
**wssend**
**zip**
```
zip (output file name), input1 [, input n]
```
## Agent msh options
You can find a full list of options for the agent [here](https://github.com/Ylianst/MeshAgent?tab=readme-ov-file#msh-format)
`skipmaccheck=1`: Will not regenerate the agents nodeid and cause duplication of the agent when the MAC address changes.
You can add options to your .msh on agent install with [this](https://github.com/Ylianst/MeshCentral/blob/15ff7d12a1e4e5d78936b473ea207b7e02b8ff26/meshcentral-config-schema.json#L2504)

View file

@ -14,30 +14,12 @@
![agent invite code](images/assistant_agent_code.png) ![agent invite code](images/assistant_agent_code.png)
## Agent Invitation ## Agent Invitation Link
Click on the 'Invite' button next to the device group name to access it.
### Link Invitation For web page customization:
For link invitation web page customization:
1. Alongside `meshcentral-data` create a folder called `meshcentral-web` 1. Alongside `meshcentral-data` create a folder called `meshcentral-web`
2. Create a `views` folder in it and copy the file `node_modules/meshcentral/views/invite.handlebars` into it. 2. Create a `views` folder in it and copy the file `node_modules/meshcentral/views/invite.handlebars` into it.
3. That copy will be served instead of the default one, so you can customize it as you want. 3. That copy will be served instead of the default one, you can customize as you want.
![agent invite code](images/assistant_invitation_link.png) ![agent invite code](images/assistant_invitation_link.png)
### Email Invitation
This option will show up if you have an SMTP email server set up with MeshCentral.
For invitation email customization:
1. Alongside `meshcentral-data` create a folder called `meshcentral-web`
2. Create an `emails` folder in it and copy the files `node_modules/meshcentral/emails/mesh-invite.txt` and `node_modules/meshcentral/emails/mesh-invite.html` into it.
3. These copies will be used instead of the default ones, so you can customize them as you want.
![email-invitation](images/email-invitation.png)
## Email notification
You can also get an email notification when someone clicks the "Request Help" button in the Assistant agent.
![](images/2022-09-06-16-38-57.png)

View file

@ -73,29 +73,11 @@ When doing sign/unsign, you can also change resource properties of the generated
## Automatic Agent Code Signing ## Automatic Agent Code Signing
If you want to self-sign the mesh agent so you can whitelist the software in your AV, as well as lock it to your server and organization: If you want to self-sign the mesh agent so you can whitelist the software in your AV, and lock it to your server and organization.
<div class="video-wrapper"> <div class="video-wrapper">
<iframe width="320" height="180" src="https://www.youtube.com/embed/qMAestNgCwc" frameborder="0" allowfullscreen></iframe> <iframe width="320" height="180" src="https://www.youtube.com/embed/qMAestNgCwc" frameborder="0" allowfullscreen></iframe>
</div> </div>
!!!note !!!note
If you generate your private key on windows with use `BEGIN PRIVATE KEY` and openssl needs `BEGIN RSA PRIVATE KEY` you can convert your private key to rsa private key using `openssl rsa -in server.key -out server_new.key` If you generate your private key on windows with use `BEGIN PRIVATE KEY` and openssl needs `BEGIN RSA PRIVATE KEY` you can convert your private key to rsa private key using `openssl rsa -in server.key -out server_new.key`
## Setting Agent File info
Now that MeshCentral customizes and signs the agent, you can set that value to anything you like.
```json
"domains": {
"agentFileInfo": {
"filedescription": "sample_filedescription",
"fileversion": "0.1.2.3",
"internalname": "sample_internalname",
"legalcopyright": "sample_legalcopyright",
"originalfilename": "sample_originalfilename",
"productname": "sample_productname",
"productversion": "v0.1.2.3"
}
}
```

File diff suppressed because it is too large Load diff

View file

@ -1,105 +0,0 @@
# Customization
Whitelabeling your MeshCentral installation to personalize it to your company's brand, as well as having your own terms of use is one of the first things many people do after installation.
<div class="video-wrapper">
<iframe width="320" height="180" src="https://www.youtube.com/embed/xUZ1w9RSKpQ" frameborder="0" allowfullscreen></iframe>
</div>
## Web Branding
You can put your own logo on the top of the web page. To get started, get the file “logoback.png” from the folder “node_modules/meshcentral/public/images” and copy it to your “meshcentral-data” folder. In this example, we will change the name of the file “logoback.png” to “title-mycompany.png”. Then use any image editor to change the image and place your logo.
![](images/2022-05-19-00-38-51.png)
Once done, edit the config.json file and set one or all of the following values:
```json
"domains": {
"": {
"Title": "",
"Title2": "",
"TitlePicture": "title-sample.png",
"loginPicture": "logintitle-sample.png",
"welcomeText": "This is sample text",
"welcomePicture": "mainwelcome-04.jpg",
"welcomePictureFullScreen": true,
"siteStyle": "1",
"nightMode": "1",
"meshMessengerTitle": "Mesh Chat",
"meshMessengerPicture": "chatimage.png",
"footer": "This is a HTML string displayed at the bottom of the web page when a user is logged in.",
"loginfooter": "This is a HTML string displayed at the bottom of the web page when a user is not logged in."
},
```
This will set the title and sub-title text to empty and set the background image to the new title picture file. You can now restart the server and take a look at the web page. Both the desktop and mobile sites will change.
![](images/2022-05-19-00-39-35.png)
![](images/2022-05-19-00-39-42.png)
The title image must a PNG image of size 450 x 66.
You can also customize the server icon in the “My Server” tab. By default, its a picture of a desktop with a padlock.
![](images/2022-05-19-00-40-00.png)
If, for example, MeshCentral is running on a Raspberry Pi. You may want to put a different picture at this location. Just put a “server.jpg” file that is 200 x 200 pixels in the “meshcentral-data” folder. The time MeshCentral page is loaded, you will see the new image.
![](images/2022-05-19-00-40-13.png)
This is great to personalize the look of the server within the web site.
### Customizing Web Icons
MeshCentral lets you change the icons for different devices shown in the Web User Interface. To do this the proper way, you should make a new folder called `meshcentral-web` in the main directory, where you find other folders like `meshcentral-data`, `meshcentral-backup`, `meshcentral-files`, and `node-modules`. Inside `meshcentral-web`, make another folder named `public` and copy the entire `node_modules/meshcentral/public/images` folder into this new `meshcentral-web/public` folder and then edit the files in `meshcentral-web/public/images/`. This step is suggested because if MeshCentral updates, it might delete any changes in `node_modules`. But, changes in `meshcentral-web` will stay safe, and MeshCentral will use these files instead of the originals in `node_modules`.
To update device icons, you need to edit these files: `meshcentral-web/public/images/webp/iconsXX.webp` (`icons16.webp`, `icons32.webp`, `icons50.webp`, `icons100.webp`), and `meshcentral-web/public/images/iconsXX.png` (`icons16.png`, `icons32.png`, `icons50.png`, `icons64.png`, `icons100.png`) and the corresponding `meshcentral-web/public/images/icons256-X-1.png`. Make sure to keep the resolution of these files as it is.
By following these steps, you can customize any icon in MeshCentral. Just find and change the corresponding image files in the `meshcentral-web/public/images` folder. Similarly, you can also move other folders from `node_modules/meshcentral` to `meshcentral-web` while keeping the original folder structure. This allows you to modify other parts of MeshCentral too, like the `.handlebars` templates for the web interface. Simply copy files from `node_modules/meshcentral/views` to `meshcentral-web/views` and make your changes in `meshcentral-web`. This lets you match MeshCentral's look to your company's brand or your own style.
![](images/custom-web-icons.png)
### Customizing Agent Invitation
Agents can be invited by public link or via email. [Click Here](assistant.md#agent-invitation) to see details.
## Agent Branding
You can customize the Agent to add your own logo, change the title bar, install text, the service name, or even colors!
!!!note
The Customization must be done FIRST and BEFORE you deploy your agents! Once the agents have been deployed, any customization made afterwards, will not sync! This is because the setup files are customized on the fly, then when you install the agents, the exe and .msh file with the customizations in are copied over to the required folder, so you will need to reinstall the agent for agent customizations to take effect.
![](images/2022-08-24-06-42-40.png)
```json
"domains": {
"": {
"agentCustomization": {
"displayName": "MeshCentral Agent",
"description": "Mesh Agent background service",
"companyName": "Mesh Agent Company",
"serviceName": "Mesh Agent Service",
"installText": "Text string to show in the agent installation dialog box",
"image": "mylogo.png",
"fileName": "meshagent",
"foregroundColor": "#FFA500",
"backgroundColor": "#EE82EE"
}
}
}
```
![agent icon](images/agentico.png)
## Terms of use
You can change the terms of use of the web site by adding a “terms.txt” file in the “meshcentral-data” folder. The file can include HTML markup. Once set, the server does not need to be restarted, the updated terms.txt file will get used the next time its requested.
For example, placing this in “terms.txt”
```
<br />
This is a <b>test file</b>.
```
Will show this on the terms of use web page.

View file

@ -23,7 +23,7 @@ Make sure you understand how MeshCentral works with your browser using chrome de
### Understanding node and paths ### Understanding node and paths
Note that when running MeshCentral, you should always run from the path that is parent to node_modules, so you do this: Note that when running MeshCentral, you should always run like from the path that is parent to node_modules, so you do this:
``` ```
cd C:\Program Files\Open Source\MeshCentral cd C:\Program Files\Open Source\MeshCentral
@ -39,7 +39,7 @@ node meshcentral
The problem with the second command is that NPM may install missing modules in the incorrect location. The problem with the second command is that NPM may install missing modules in the incorrect location.
Also, in general I recommend not using the MeshCentral MSI Installer and just install manually unless you are very scared of the command prompt. Anyone that knows a bit about the shell should install MeshCentral like this: Also, in general I recommend not using the MeshCentral MSI Installer and just install manually unless you are very much scared of the command prompt. Anyone that knows about bit about the shell should install MeshCentral like this:
``` ```
mkdir c:\meshcentral mkdir c:\meshcentral
@ -50,11 +50,11 @@ node node_modules\meshcentral
node node_modules\meshcentral --install node node_modules\meshcentral --install
``` ```
This way, you have a lot more control over what is going on. In my opinion, the MSI installer basically does the same thing and installs NodeJS for you. This way, just have a lot more control over what is going on. Just my opinion, the MSI installer basically does the same thing and installs NodeJS for you.
### Unable to update server ### Unable to update server
Generally the problem is that MeshCentral can't find the npm tool and therefore, can't run it to see if there is a new version. You can fix this by setting the path to npm in the config.json like this: Generally the problem is that MeshCentral can't find the npm tool and so, can't run it to see if there is a new version. You can fix this by setting the path to npm in the config.json like this:
```json ```json
{ {
@ -86,59 +86,14 @@ node node_modules/meshcentral --stop
### Port Troubleshooting on server ### Port Troubleshooting on server
If you're getting a `port 4433 is not available` error, this is because another process is using this port, very likely another instance of MeshCentral. If your MeshCentral server is bound to ports 81/444 MeshCentral could not get port 80/443 and got the next available ones. If you're getting a `port 4433 is not available` error, this is because someone else is using this port, very likely another instance of MeshCentral. If your MeshCentral server is bound to ports 81/444 MeshCentral could not get port 80/443 and got the next available ones.
In general the problem is that you are running two MeshCentral instances at the same time. Probably one as a background Windows Service and one in the command line. Which ever instance can grab port 4433 will have a running MPS and CIRA should work, but the second instance will not have port 4433 and CIRA will not work. In general the problem is that you are running two MeshCentral instances at the same time. Probably one as a background Windows Service and one in the command line. Which ever instance can grab port 4433 will have a running MPS and CIRA should work, but the second instance will not have port 4433 and CIRA will not work.
### Running Meshcentral server in debug mode
Debug more will cause MeshCentral to output a lot of debug messages to the console. To display all debug messages, run MeshCentral like this:
```bash
node node_modules/meshcentral --debug
```
A more practical way to run the debug command it to specify what messages you want printed out using a comma seperated list, for example:
```bash
node node_modules/meshcentral --debug web,amt,mps
```
Here is the list of all debug options:
```
cookie - Cookie encoder
dispatch - Message Dispatcher
main - Main Server Messages
peer - MeshCentral Server Peering
agent - MeshAgent traffic
agentupdate - MeshAgent update
cert - Server Certificate
db - Server Database
email - Email/SMS/Push Traffic
web - Web Server
webrequest - Web Server Requests
relay - Web Socket Relay
httpheaders - Web Server HTTP Headers
authlog - User Authentication Log
amt - Intel AMT
webrelay - Connection Relay
mps - CIRA Server
mpscmd - CIRA Server Commands
```
You can also specify the `debug` option in the config.json file in the `settings` section. For example:
```
"settings": {
"debug": "web,amt,mps"
}
```
### Enabling trace in your browser Dev Tools ### Enabling trace in your browser Dev Tools
You can enable browser console tracing by adding `trace=1` as a parameter to the URL of the MeshCentral main web page. For example `https://myserver.com/?trace=1`. Once present, open the browser's console window to see all web client tracing messages. `Trace=1` as a parameter in chrome dev tools for debugging
To log all database queries, change log_statement in /etc/postgresql/13/main/postgresql.conf To log all database queries, change log_statement in /etc/postgresql/13/main/postgresql.conf

View file

@ -1,23 +1,5 @@
# Device Tabs # Device Tabs
## Search or Filter
You can search your list of agents using any of these criteria using the filter box (also viewable in the tooltip of the Filter box):
user:xxx or u:xxx
ip:xxx
group:xxx or g:xxx
tag:xxx or t:xxx
atag:xxx or a:xxx
os:xxx
amt:xxx
desc:xxx
wsc:ok
wsc:noav
wsc:noupdate
wsc:nofirewall
wsc:any
## General ## General
For viewing general information about the agent For viewing general information about the agent
@ -54,11 +36,10 @@ Chat
Legend Legend
* **_Black color_**: Device is Powered On on (Intel AMT & agents) * **_Black color_**: Device is powered on (Intel AMT & agents)
* **_Purple color_**: Device is in sleep state such as Hibernating (Intel AMT agents only) * **_Purple color_**: Device is in sleep state (Intel AMT agents only)
* **_Teal color_**: Device is connected through AMT/CIRA, but the Power State is UNKNOWN (Intel AMT agents only) * **_Teal color_**: Device is connected through AMT/CIRA, but not powered on (Intel AMT agents only)
* **_DarkGreen color_**: Device is connected through AMT/CIRA and is in Soft-Off Power State (Intel AMT agents only) * **_Grey color_**: Device is powered off (Intel AMT & agents)
* **_Grey color_**: Device is Powered Off/Not Connected To MeshCentral (Intel AMT & agents)
### Text Links ### Text Links
@ -211,60 +192,3 @@ Note you can show CPU and Memory usage info by clicking the icon in the top righ
For debugging and communicating with the mesh agent. For debugging and communicating with the mesh agent.
It allows JS commands to be issued to the device but also run extra commands from the meshcore. Type `help` for all available options It allows JS commands to be issued to the device but also run extra commands from the meshcore. Type `help` for all available options
- 2falock
- acceleratorsstats
- agentissues
- agentstats
- amtacm
- amtmanager
- amtpasswords
- amtstats
- args
- autobackup
- backupconfig
- bad2fa
- badlogins
- certexpire
- certhashes
- closeusersessions
- cores
- dbcounters
- dbstats
- dispatchtable
- dropallcira
- dupagents
- email
- emailnotifications
- firebase
- heapdump
- heapdump2
- help
- info
- le
- lecheck
- leevents
- maintenance
- migrationagents
- mps
- mpsstats
- msg
- nodeconfig
- print
- relays
- removeinactivedevices
- resetserver
- serverupdate
- setmaxtasks
- showpaths
- sms
- swarmstats
- tasklimiter
- trafficdelta
- trafficstats
- updatecheck
- usersessions
- versions
- watchdog
- webpush
- webstats

View file

@ -1,83 +0,0 @@
# FAQ
## json config files
Any item in the config.json file starting with an underscore character are ignored.
Ignored
```json
"_title": "MyServer"
```
Valid setting
```json
"title": "MyServer"
```
json requires correct formatting, if in doubt copy/paste your json config into a web based format checker to make sure you have it right: <https://duckduckgo.com/?va=j&t=hc&q=json+lint&ia=answer>
## Help! I've been hacked there are weird agents appearing in my MeshCentral Console
No, you haven't.
1. Your agent installer was scanned by an antivirus.
2. It didn't recognize the exe.
3. You have the option enabled to submit unknown applications for analysis.
![AV Option1](images/faq_av_option1.png)
4. They ran it against their virtualization testing cluster.
5. You allow anyone to connect to your server (you should look into techniques to hide your server from the internet).
6. Here are some examples of what that looks like.
## Can't login on server after first setup
You're sure you're typing in everything right, giving it 2FA code and can't login
[TOTP](https://en.wikipedia.org/wiki/Time-based_one-time_password) is time sensitive, check your time/NTP and make sure it's right (on server and TOTP app device)! :)
![](images/2022-08-04-18-19-19.png)
## Branding and Customization
You can brand and customize MeshCentral almost as much as you like without delving into the code, a few changes in the config.json file and uploading images can change the way your system looks. Read more [here](https://ylianst.github.io/MeshCentral/meshcentral/#branding-terms-of-use)
!!!note
You will need to reinstall the agent for agent customizations to take effect.
## Mac Clients
You have to manually grant Mac permissions outside of the agent install process due to the MacOS security system under Security & Privacy > Privacy
To see the screen (otherwise you just see the menu bar, and otherwise blank)
![](images/2023-11-29-12-57-15.png)
To be able to transfer files
![](images/2023-11-29-12-58-05.png)
To be able to control keyboard and mouse
![](images/2023-11-29-12-58-36.png)
## I'm using CloudFlare and I'm getting a black screen but the mouse moves?
If you are using CloudFlare for your DNS hosting and your remote screen is black, DONT PANIC!
Unfortunately, MeshCentral doesn't always work with CloudFlare's Proxy DNS Mode.
The fix is to simply set the 'Proxy Status' to OFF inside your DNS A Record, within the CloudFlare control panel.
Simply follow the steps [here](https://developers.cloudflare.com/fundamentals/setup/manage-domains/pause-cloudflare/#disable-proxy-on-dns-records)
Once done, open your firewall for the `port` and `agentPort` ports of where your meshcentral is hosted, then restart your MeshCentral Server
There is currently a PINNED GitHub issue about this [here](https://github.com/Ylianst/MeshCentral/issues/5302)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

Some files were not shown because too many files have changed in this diff Show more