Compare commits
15 Commits
9d0b983596
...
a3aecdc72b
Author | SHA1 | Date |
---|---|---|
Simon Smith | a3aecdc72b | |
Simon Smith | 56d6527bf5 | |
adnan29979 | 3ce2fd92c0 | |
adnan29979 | eb27334b82 | |
si458 | 414d9b9561 | |
si458 | 1747ff7550 | |
si458 | f39b6f8859 | |
Simon Smith | ca868afdd1 | |
Simon Smith | 410c84c30b | |
Attocode1 | 18b731fd36 | |
si458 | 832e618602 | |
si458 | 7b8cf85740 | |
si458 | 1dca9e2235 | |
Simon Smith | 30d570f28b | |
si458 | eda42cf406 |
38
db.js
38
db.js
|
@ -733,22 +733,34 @@ module.exports.CreateDB = function (parent, func) {
|
|||
});
|
||||
} else if (parent.args.mariadb || parent.args.mysql) {
|
||||
var connectinArgs = (parent.args.mariadb) ? parent.args.mariadb : parent.args.mysql;
|
||||
var dbname = (connectinArgs.database != null) ? connectinArgs.database : 'meshcentral';
|
||||
if (typeof connectinArgs == 'string') {
|
||||
const parts = connectinArgs.split(/[:@/]+/);
|
||||
var connectionObject = {
|
||||
"user": parts[1],
|
||||
"password": parts[2],
|
||||
"host": parts[3],
|
||||
"port": parts[4],
|
||||
"database": parts[5]
|
||||
};
|
||||
var dbname = (connectionObject.database != null) ? connectionObject.database : 'meshcentral';
|
||||
} else {
|
||||
var dbname = (connectinArgs.database != null) ? connectinArgs.database : 'meshcentral';
|
||||
|
||||
// Including the db name in the connection obj will cause a connection faliure if it does not exist
|
||||
var connectionObject = Clone(connectinArgs);
|
||||
delete connectionObject.database;
|
||||
// Including the db name in the connection obj will cause a connection faliure if it does not exist
|
||||
var connectionObject = Clone(connectinArgs);
|
||||
delete connectionObject.database;
|
||||
|
||||
try {
|
||||
if (connectinArgs.ssl) {
|
||||
if (connectinArgs.ssl.dontcheckserveridentity == true) { connectionObject.ssl.checkServerIdentity = function (name, cert) { return undefined; } };
|
||||
if (connectinArgs.ssl.cacertpath) { connectionObject.ssl.ca = [require('fs').readFileSync(connectinArgs.ssl.cacertpath, 'utf8')]; }
|
||||
if (connectinArgs.ssl.clientcertpath) { connectionObject.ssl.cert = [require('fs').readFileSync(connectinArgs.ssl.clientcertpath, 'utf8')]; }
|
||||
if (connectinArgs.ssl.clientkeypath) { connectionObject.ssl.key = [require('fs').readFileSync(connectinArgs.ssl.clientkeypath, 'utf8')]; }
|
||||
try {
|
||||
if (connectinArgs.ssl) {
|
||||
if (connectinArgs.ssl.dontcheckserveridentity == true) { connectionObject.ssl.checkServerIdentity = function (name, cert) { return undefined; } };
|
||||
if (connectinArgs.ssl.cacertpath) { connectionObject.ssl.ca = [require('fs').readFileSync(connectinArgs.ssl.cacertpath, 'utf8')]; }
|
||||
if (connectinArgs.ssl.clientcertpath) { connectionObject.ssl.cert = [require('fs').readFileSync(connectinArgs.ssl.clientcertpath, 'utf8')]; }
|
||||
if (connectinArgs.ssl.clientkeypath) { connectionObject.ssl.key = [require('fs').readFileSync(connectinArgs.ssl.clientkeypath, 'utf8')]; }
|
||||
}
|
||||
} catch (ex) {
|
||||
console.log('Error loading SQL Connector certificate: ' + ex);
|
||||
process.exit();
|
||||
}
|
||||
} catch (ex) {
|
||||
console.log('Error loading SQL Connector certificate: ' + ex);
|
||||
process.exit();
|
||||
}
|
||||
|
||||
if (parent.args.mariadb) {
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -0,0 +1,56 @@
|
|||
# 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 you’ve 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 project’s 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:** It’s 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.
|
|
@ -895,7 +895,7 @@ The last line will run MeshCentral manually and allow it to install any missing
|
|||
|
||||
```
|
||||
sudo chown -R meshcentral:meshcentral /opt/meshcentral
|
||||
sudo chmod 755 –R /opt/meshcentral/meshcentral-*
|
||||
sudo chmod -R 755 /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:
|
||||
|
@ -912,7 +912,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 server’s `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 755 –R /opt/meshcentral/meshcentral-files
|
||||
sudo chmod -R 755 /opt/meshcentral/meshcentral-files
|
||||
```
|
||||
|
||||
If you plan on using the increased security installation along with MeshCentral built-in Let’s Encrypt support you will need to type the following commands to make the `letsencrypt` folder in `meshcentral-data` writable.
|
||||
|
@ -920,7 +920,7 @@ If you plan on using the increased security installation along with MeshCentral
|
|||
```
|
||||
sudo mkdir /opt/meshcentral/meshcentral-data
|
||||
sudo mkdir /opt/meshcentral/meshcentral-data/letsencrypt
|
||||
sudo chmod 755 –R /opt/meshcentral/meshcentral-data/letsencrypt
|
||||
sudo chmod -R 755 /opt/meshcentral/meshcentral-data/letsencrypt
|
||||
```
|
||||
|
||||
This will allow the server to get and periodically update its Let’s Encrypt certificate. If this is not done, the server will generate an `ACCES: permission denied` exception.
|
||||
|
|
|
@ -317,7 +317,12 @@ The password recovery flow when “Reset Account” is triggered at the login pa
|
|||
|
||||
![](images/2022-05-19-00-00-18.png)
|
||||
|
||||
Both account verification and password recovery are triggered automatically once SMTP mail server configuration is included into the config.json file. Update the config.json with “smtp” section as shown below and restart the server.
|
||||
Both account verification and password recovery are triggered automatically once SMTP mail server configuration is included into the config.json file.
|
||||
|
||||
#### SMTP: User/Pass
|
||||
##### Normal Server
|
||||
|
||||
Update the config.json with “smtp” section as shown below and restart the server.
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -325,9 +330,9 @@ Both account verification and password recovery are triggered automatically once
|
|||
"host": "smtp.server.com",
|
||||
"port": 25,
|
||||
"from": "myaddress@server.com",
|
||||
"user": "myaddress@server.com", Optional
|
||||
"pass": "mypassword", Optional
|
||||
"tls": false Optional, default false
|
||||
"user": "myaddress@server.com", # Optional
|
||||
"pass": "mypassword", # Optional
|
||||
"tls": false # Optional, default false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -336,7 +341,6 @@ Please map the host, port values to connect to the right host that provides this
|
|||
|
||||
Some SMTP servers will require a valid username and password to login to the mail server. This is to prevent unauthorized e-mail correspondence. TLS option can be set to ‘true’ if the SMTP server requires TLS.
|
||||
|
||||
#### SMTP: User/Pass
|
||||
##### Gmail
|
||||
|
||||
One option is to configure MeshCentral work with Google Gmail by setting “host” with smtp.gmail.com, and “port” with 587. In the config.json file, use user’s Gmail address for both “from” and “user” and Gmail password in the “pass” value. You will also need to enable “Less secure app access” in for this Google account. It’s in the account settings, security section:
|
||||
|
@ -548,14 +552,14 @@ To make this happen, we will be using the following command line options from Me
|
|||
| --dblistconfigfiles | List the names and size of all configuration files in the database. |
|
||||
| --dbshowconfigfile (filename) | Show the content of a specified filename from the database. --configkey is required. |
|
||||
| --dbdeleteconfigfiles | Delete all configuration files from the database. |
|
||||
| --dbpushconfigfiles (*) or (folder path) | Push a set of configuration files into the database, removing any existing files in the process. When * is specified, the “meshcentral-data” folder up pushed into the database. --configkey is required. |
|
||||
| --dbpushconfigfiles '*' or (folder path) | Push a set of configuration files into the database, removing any existing files in the process. When * is specified, the “meshcentral-data” folder up pushed into the database. --configkey is required. |
|
||||
| --dbpullconfigfiles (folder path) | Get all of the configuration files from the database and place them in the specified folder. Files in the target folder may be overwritten. --configkey is required. |
|
||||
| --loadconfigfromdb (key) | Runs MeshCentral server using the configuration files found in the database. The configkey may be specified with this command or --configkey can be used. |
|
||||
|
||||
Once we have MeshCentral running as expected using the “meshcentral-data” folder, we can simply push that configuration into the database and run using the database alone like this:
|
||||
|
||||
```
|
||||
node ./node_modules/meshcentral --dbpushconfigfiles * --configkey mypassword
|
||||
node ./node_modules/meshcentral --dbpushconfigfiles '*' --configkey mypassword
|
||||
|
||||
node ./node_modules/meshcentral --loadconfigfromdb mypassword --mongodb "mongodb://127.0.0.1:27017/meshcentral"
|
||||
```
|
||||
|
|
|
@ -38,6 +38,9 @@ nav:
|
|||
- Intel AMT:
|
||||
- intelamt/index.md
|
||||
|
||||
- How to Contribute:
|
||||
- how-to-contribute/index.md
|
||||
|
||||
- Other:
|
||||
- other/adfs_sso_guide.md
|
||||
- other/meshcentral_satellite.md
|
||||
|
|
|
@ -2677,7 +2677,7 @@
|
|||
"name": {
|
||||
"type": "string",
|
||||
"format": "hostname",
|
||||
"description": "Optional hostname of the client, this defaults to the hostname of the machine. This is useful for SMTP relays."
|
||||
"description": "Optional hostname of the client, this defaults to the hostname of the machine. This is useful for SMTP relays. This can also be set to \"console\" for console output debugging."
|
||||
},
|
||||
"host": {
|
||||
"type": "string",
|
||||
|
@ -2688,18 +2688,32 @@
|
|||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535,
|
||||
"description": "SMTP server port number."
|
||||
"default": 587,
|
||||
"description": "SMTP server port number. This defaults to 587 if \"tls\" is false or 465 if \"tls\" is true)"
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Email address used in the messages from field."
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "SMTP username."
|
||||
},
|
||||
"pass": {
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "SMTP password."
|
||||
},
|
||||
"tls": {
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Set SMTP to use TLS on connections, the default is false"
|
||||
},
|
||||
"auth": {
|
||||
"type": "object",
|
||||
"description": "This is used for OAuth2 authentication",
|
||||
"properties": {
|
||||
"clientId": {
|
||||
"type": "string"
|
||||
|
@ -2709,6 +2723,11 @@
|
|||
},
|
||||
"refreshToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"default": "login",
|
||||
"description": "Setting this indicates the authetication type, 'login' as default or 'oauth2'"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
@ -2735,7 +2754,10 @@
|
|||
}
|
||||
},
|
||||
"required": [
|
||||
"from"
|
||||
"host",
|
||||
"port",
|
||||
"from",
|
||||
"tls"
|
||||
]
|
||||
},
|
||||
"sendmail": {
|
||||
|
@ -3558,22 +3580,67 @@
|
|||
"description": "Connects MeshCentral to a SMTP email server, allows MeshCentral to send email messages for 2FA or user notification.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"format": "hostname",
|
||||
"description": "Optional hostname of the client, this defaults to the hostname of the machine. This is useful for SMTP relays. This can also be set to \"console\" for console output debugging."
|
||||
},
|
||||
"host": {
|
||||
"type": "string",
|
||||
"format": "hostname"
|
||||
"format": "hostname",
|
||||
"description": "Hostname of the SMTP server."
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
"maximum": 65535,
|
||||
"default": 587,
|
||||
"description": "SMTP server port number. This defaults to 587 if \"tls\" is false or 465 if \"tls\" is true)"
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Email address used in the messages from field."
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "SMTP username."
|
||||
},
|
||||
"pass": {
|
||||
"type": "string",
|
||||
"format": "string",
|
||||
"description": "SMTP password."
|
||||
},
|
||||
"tls": {
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Set SMTP to use TLS on connections, the default is false"
|
||||
},
|
||||
"auth": {
|
||||
"type": "object",
|
||||
"description": "This is used for OAuth2 authentication",
|
||||
"properties": {
|
||||
"clientId": {
|
||||
"type": "string"
|
||||
},
|
||||
"clientSecret": {
|
||||
"type": "string"
|
||||
},
|
||||
"refreshToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"default": "login",
|
||||
"description": "Setting this indicates the authetication type, 'login' as default or 'oauth2'"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"clientId",
|
||||
"clientSecret",
|
||||
"refreshToken"
|
||||
]
|
||||
},
|
||||
"tlscertcheck": {
|
||||
"type": "boolean"
|
||||
|
@ -3585,6 +3652,11 @@
|
|||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "When set to false, the email format and DNS MX record are not checked."
|
||||
},
|
||||
"emailDelaySeconds": {
|
||||
"type": "integer",
|
||||
"default": 300,
|
||||
"description": "Time to wait before sending a device connection/disconnection notification email. If many events occur, they will be merged into a single email."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
@ -3594,6 +3666,36 @@
|
|||
"tls"
|
||||
]
|
||||
},
|
||||
"sendmail": {
|
||||
"title": "Send email using the sendmail command",
|
||||
"description": "Makes MeshCentral send emails using the Unix sendmail command. Allows MeshCentral to send email messages for 2FA or user notification.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"newline": {
|
||||
"type": "string",
|
||||
"default": "unix",
|
||||
"description": "Possible values are unix or windows"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"default": "sendmail",
|
||||
"description": "Path to the sendmail command"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": null,
|
||||
"description": "Array or arguments to pass to sendmail"
|
||||
},
|
||||
"emailDelaySeconds": {
|
||||
"type": "integer",
|
||||
"default": 300,
|
||||
"description": "Time to wait before sending a device connection/disconnection notification email. If many events occur, they will be merged into a single email."
|
||||
}
|
||||
}
|
||||
},
|
||||
"sms": {
|
||||
"title": "SMS provider",
|
||||
"description": "Connects MeshCentral to a SMS text messaging provider, allows MeshCentral to send SMS messages for 2FA or user notification.",
|
||||
|
|
|
@ -139,9 +139,11 @@ function CreateMeshCentralServer(config, args) {
|
|||
try { require('./pass').hash('test', function () { }, 0); } catch (ex) { console.log('Old version of node, must upgrade.'); return; } // TODO: Not sure if this test works or not.
|
||||
|
||||
// Check for invalid arguments
|
||||
const validArguments = ['_', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'showitem', 'listuserids', 'showusergroups', 'shownodes', 'showallmeshes', 'showmeshes', 'showevents', 'showsmbios', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'xinstall', 'xuninstall', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbfix', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'usenodedefaulttlsciphers', 'tlsciphers', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name', 'log', 'dbstats', 'translate', 'createaccount', 'setuptelegram', 'resetaccount', 'pass', 'removesubdomain', 'adminaccount', 'domain', 'email', 'configfile', 'maintenancemode', 'nedbtodb', 'removetestagents', 'agentupdatetest', 'hashpassword', 'hashpass', 'indexmcrec', 'mpsdebug', 'dumpcores', 'dev'];
|
||||
const validArguments = ['_', 'user', 'port', 'aliasport', 'mpsport', 'mpsaliasport', 'redirport', 'rediraliasport', 'cert', 'mpscert', 'deletedomain', 'deletedefaultdomain', 'showall', 'showusers', 'showitem', 'listuserids', 'showusergroups', 'shownodes', 'showallmeshes', 'showmeshes', 'showevents', 'showsmbios', 'showpower', 'clearpower', 'showiplocations', 'help', 'exactports', 'xinstall', 'xuninstall', 'install', 'uninstall', 'start', 'stop', 'restart', 'debug', 'filespath', 'datapath', 'noagentupdate', 'launch', 'noserverbackup', 'mongodb', 'mongodbcol', 'wanonly', 'lanonly', 'nousers', 'mpspass', 'ciralocalfqdn', 'dbexport', 'dbexportmin', 'dbimport', 'dbmerge', 'dbfix', 'dbencryptkey', 'selfupdate', 'tlsoffload', 'usenodedefaulttlsciphers', 'tlsciphers', 'userallowedip', 'userblockedip', 'swarmallowedip', 'agentallowedip', 'agentblockedip', 'fastcert', 'swarmport', 'logintoken', 'logintokenkey', 'logintokengen', 'mailtokengen', 'admin', 'unadmin', 'sessionkey', 'sessiontime', 'minify', 'minifycore', 'dblistconfigfiles', 'dbshowconfigfile', 'dbpushconfigfiles', 'dbpullconfigfiles', 'dbdeleteconfigfiles', 'vaultpushconfigfiles', 'vaultpullconfigfiles', 'vaultdeleteconfigfiles', 'configkey', 'loadconfigfromdb', 'npmpath', 'serverid', 'recordencryptionrecode', 'vault', 'token', 'unsealkey', 'name', 'log', 'dbstats', 'translate', 'createaccount', 'setuptelegram', 'resetaccount', 'pass', 'removesubdomain', 'adminaccount', 'domain', 'email', 'configfile', 'maintenancemode', 'nedbtodb', 'removetestagents', 'agentupdatetest', 'hashpassword', 'hashpass', 'indexmcrec', 'mpsdebug', 'dumpcores', 'dev', 'mysql', 'mariadb'];
|
||||
for (var arg in obj.args) { obj.args[arg.toLocaleLowerCase()] = obj.args[arg]; if (validArguments.indexOf(arg.toLocaleLowerCase()) == -1) { console.log('Invalid argument "' + arg + '", use --help.'); return; } }
|
||||
if (obj.args.mongodb == true) { console.log('Must specify: --mongodb [connectionstring] \r\nSee https://docs.mongodb.com/manual/reference/connection-string/ for MongoDB connection string.'); return; }
|
||||
if (obj.args.mysql == true) { console.log('Must specify: --mysql [connectionstring] \r\nExample mysql://user:password@127.0.0.1:3306/database'); return; }
|
||||
if (obj.args.mariadb == true) { console.log('Must specify: --mariadb [connectionstring] \r\nExample mariadb://user:password@127.0.0.1:3306/database'); return; }
|
||||
for (i in obj.config.settings) { obj.args[i] = obj.config.settings[i]; } // Place all settings into arguments, arguments have already been placed into settings so arguments take precedence.
|
||||
|
||||
if ((obj.args.help == true) || (obj.args['?'] == true)) {
|
||||
|
@ -220,6 +222,12 @@ function CreateMeshCentralServer(config, args) {
|
|||
translateEngine.startEx(['', '', 'translateall', translationFile]);
|
||||
translateEngine.startEx(['', '', 'extractall', translationFile]);
|
||||
didSomething = true;
|
||||
} else {
|
||||
// Translate all of the default files
|
||||
translateEngine.startEx(['', '', 'minifyall']);
|
||||
translateEngine.startEx(['', '', 'translateall']);
|
||||
translateEngine.startEx(['', '', 'extractall']);
|
||||
didSomething = true;
|
||||
}
|
||||
|
||||
// Check if "meshcentral-web" exists, if so, translate all pages in that folder.
|
||||
|
@ -235,11 +243,34 @@ function CreateMeshCentralServer(config, args) {
|
|||
files = obj.fs.readdirSync(obj.webViewsOverridePath);
|
||||
for (var i in files) {
|
||||
var file = obj.path.join(obj.webViewsOverridePath, files[i]);
|
||||
if (file.endsWith('.handlebars') || file.endsWith('-min.handlebars')) {
|
||||
if (file.endsWith('.handlebars') && !file.endsWith('-min.handlebars')) {
|
||||
translateEngine.startEx(['', '', 'translate', '*', translationFile, file, '--subdir:translations']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check domains and see if "meshcentral-web-DOMAIN" exists, if so, translate all pages in that folder
|
||||
for (i in obj.config.domains) {
|
||||
if (i == "") continue;
|
||||
var path = obj.path.join(obj.datapath, '..', 'meshcentral-web-' + i, 'views');
|
||||
if (require('fs').existsSync(path)) {
|
||||
didSomething = true;
|
||||
var files = obj.fs.readdirSync(path);
|
||||
for (var a in files) {
|
||||
var file = obj.path.join(path, files[a]);
|
||||
if (file.endsWith('.handlebars') && !file.endsWith('-min.handlebars')) {
|
||||
translateEngine.startEx(['', '', 'minify', file]);
|
||||
}
|
||||
}
|
||||
files = obj.fs.readdirSync(path);
|
||||
for (var a in files) {
|
||||
var file = obj.path.join(path, files[a]);
|
||||
if (file.endsWith('.handlebars') && !file.endsWith('-min.handlebars')) {
|
||||
translateEngine.startEx(['', '', 'translate', '*', translationFile, file, '--subdir:translations']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (obj.webPublicOverridePath != null) {
|
||||
didSomething = true;
|
||||
|
@ -254,6 +285,7 @@ function CreateMeshCentralServer(config, args) {
|
|||
*/
|
||||
|
||||
if (didSomething == false) { console.log("Nothing to do."); }
|
||||
console.log('Finished Translating.')
|
||||
process.exit();
|
||||
return;
|
||||
}
|
||||
|
@ -3936,8 +3968,8 @@ var meshserver = null;
|
|||
var childProcess = null;
|
||||
var previouslyInstalledModules = {};
|
||||
function mainStart() {
|
||||
// Check the NodeJS is version 10 or better.
|
||||
if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) < 11) { console.log("MeshCentral requires Node v11 or above, current version is " + process.version + "."); return; }
|
||||
// Check the NodeJS is version 16 or better.
|
||||
if (Number(process.version.match(/^v(\d+\.\d+)/)[1]) < 16) { console.log("MeshCentral requires Node v16 or above, current version is " + process.version + "."); return; }
|
||||
|
||||
// If running within the node_modules folder, move working directory to the parent of the node_modules folder.
|
||||
if (__dirname.endsWith('\\node_modules\\meshcentral') || __dirname.endsWith('/node_modules/meshcentral')) { process.chdir(require('path').join(__dirname, '..', '..')); }
|
||||
|
@ -4012,6 +4044,7 @@ function mainStart() {
|
|||
|| ((Math.floor(nodeVersion) == 14) && (nodeVersion >= 14.15))
|
||||
|| ((Math.floor(nodeVersion) == 12) && (nodeVersion >= 12.19))) {
|
||||
passport.push('openid-client');
|
||||
passport.push('connect-flash');
|
||||
} else {
|
||||
addServerWarning('This NodeJS version does not support OpenID Connect on MeshCentral.', 25);
|
||||
delete config.domains[i].authstrategies.oidc;
|
||||
|
|
|
@ -1117,7 +1117,7 @@ function performConfigOperations(args) {
|
|||
if (fs.existsSync(configFile) == false) { console.log("Unable to find config.json."); return; }
|
||||
var config = null;
|
||||
try { config = fs.readFileSync(configFile).toString('utf8'); } catch (ex) { console.log("Error: Unable to read config.json"); return; }
|
||||
try { config = require(configFile); } catch (e) { console.log('ERROR: Unable to parse ' + configFile + '.'); return null; }
|
||||
try { config = JSON.parse(fs.readFileSync(configFile)); } catch (e) { console.log('ERROR: Unable to parse ' + configFile + '.'); return null; }
|
||||
if (args.adddomain != null) {
|
||||
didSomething++;
|
||||
if (config.domains == null) { config.domains = {}; }
|
||||
|
|
|
@ -5793,13 +5793,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
|
|||
return;
|
||||
}
|
||||
|
||||
for(var x in parent.users) {
|
||||
if(parent.users[x].email==command.email){
|
||||
displayNotificationMessage("Email address already in use", "New Account", "ServerNotify");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we exceed the maximum number of user accounts
|
||||
db.isMaxType(newuserdomain.limits.maxuseraccounts, 'user', newuserdomain.id, function (maxExceed) {
|
||||
if (maxExceed) {
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
"yauzl": "2.10.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=11.0.0"
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -60,32 +60,204 @@
|
|||
<input id="SaveServerButton" title="Ctrl-S" type=button value="Save to Server (F3)" onclick="saveServerTranslations()">
|
||||
<input id="SaveFileButton" title="Ctrl-Shift-S" type=button value="Save to File (F4)" onclick="saveToFile()">
|
||||
<select id="langSelector" onchange="langSelectorChange()">
|
||||
<option value="ar">Arabic (ar)</option>
|
||||
<option value="af">Afrikaans (af)</option>
|
||||
<option value="sq">Albanian (sq)</option>
|
||||
<option value="ar">Arabic (Standard) (ar)</option>
|
||||
<option value="ar-dz">Arabic (Algeria) (ar-dz)</option>
|
||||
<option value="ar-bh">Arabic (Bahrain) (ar-bh)</option>
|
||||
<option value="ar-eg">Arabic (Egypt) (ar-eg)</option>
|
||||
<option value="ar-iq">Arabic (Iraq) (ar-iq)</option>
|
||||
<option value="ar-jo">Arabic (Jordan) (ar-jo)</option>
|
||||
<option value="ar-kw">Arabic (Kuwait) (ar-kw)</option>
|
||||
<option value="ar-lb">Arabic (Lebanon) (ar-lb)</option>
|
||||
<option value="ar-ly">Arabic (Libya) (ar-ly)</option>
|
||||
<option value="ar-ma">Arabic (Morocco) (ar-ma)</option>
|
||||
<option value="ar-om">Arabic (Oman) (ar-om)</option>
|
||||
<option value="ar-qa">Arabic (Qatar) (ar-qa)</option>
|
||||
<option value="ar-sa">Arabic (Saudi Arabia) (ar-sa)</option>
|
||||
<option value="ar-sy">Arabic (Syria) (ar-sy)</option>
|
||||
<option value="ar-tn">Arabic (Tunisia) (ar-tn)</option>
|
||||
<option value="ar-ae">Arabic (U.A.E.) (ar-ae)</option>
|
||||
<option value="ar-ye">Arabic (Yemen) (ar-ye)</option>
|
||||
<option value="an">Aragonese (an)</option>
|
||||
<option value="hy">Armenian (hy)</option>
|
||||
<option value="as">Assamese (as)</option>
|
||||
<option value="ast">Asturian (ast)</option>
|
||||
<option value="az">Azerbaijani (az)</option>
|
||||
<option value="eu">Basque (eu)</option>
|
||||
<option value="bg">Bulgarian (bg)</option>
|
||||
<option value="be">Belarusian (be)</option>
|
||||
<option value="bn">Bengali (bn)</option>
|
||||
<option value="bs">Bosnian (bs)</option>
|
||||
<option value="hr">Croatian (hr)</option>
|
||||
<option value="da">Danish (da)</option>
|
||||
<option value="fi">Finnish (fi)</option>
|
||||
<option value="fr">French (fr)</option>
|
||||
<option value="cs">Czech (cs)</option>
|
||||
<option value="de">German (de)</option>
|
||||
<option value="el">Greek (el)</option>
|
||||
<option value="he">Hebrew (he)</option>
|
||||
<option value="hi">Hindi (hi)</option>
|
||||
<option value="it">Italian (it)</option>
|
||||
<option value="ja">Japanese (ja)</option>
|
||||
<option value="ko">Korean (ko)</option>
|
||||
<option value="nl">Dutch (nl)</option>
|
||||
<option value="pl">Polish (pl)</option>
|
||||
<option value="pt">Portuguese (pt)</option>
|
||||
<option value="pt-br">Portuguese Brazil (pt-br)</option>
|
||||
<option value="ru">Russian (ru)</option>
|
||||
<option value="ro">Romanian (ro)</option>
|
||||
<option value="br">Breton (br)</option>
|
||||
<option value="my">Burmese (my)</option>
|
||||
<option value="ca">Catalan (ca)</option>
|
||||
<option value="ch">Chamorro (ch)</option>
|
||||
<option value="ce">Chechen (ce)</option>
|
||||
<option value="zh">Chinese (zh)</option>
|
||||
<option value="zh-hk">Chinese (Hong Kong) (zh-hk)</option>
|
||||
<option value="zh-cn">Chinese (PRC) (zh-cn)</option>
|
||||
<option value="zh-sg">Chinese (Singapore) (zh-sg)</option>
|
||||
<option value="zh-tw">Chinese (Taiwan) (zh-tw)</option>
|
||||
<option value="zh-CHS">Simplified Chinese (zh-CHS)</option>
|
||||
<option value="zh-CHT">Traditional Chinese (zh-CHT)</option>
|
||||
<option value="cv">Chuvash (cv)</option>
|
||||
<option value="co">Corsican (co)</option>
|
||||
<option value="cr">Cree (cr)</option>
|
||||
<option value="hr">Croatian (hr)</option>
|
||||
<option value="cs">Czech (cs)</option>
|
||||
<option value="da">Danish (da)</option>
|
||||
<option value="nl">Dutch (Standard) (nl)</option>
|
||||
<option value="nl-be">Dutch (Belgian) (nl-be)</option>
|
||||
<option value="en">English (en)</option>
|
||||
<option value="en-au">English (Australia) (en-au)</option>
|
||||
<option value="en-bz">English (Belize) (en-bz)</option>
|
||||
<option value="en-ca">English (Canada) (en-ca)</option>
|
||||
<option value="en-ie">English (Ireland) (en-ie)</option>
|
||||
<option value="en-jm">English (Jamaica) (en-jm)</option>
|
||||
<option value="en-nz">English (New Zealand) (en-nz)</option>
|
||||
<option value="en-ph">English (Philippines) (en-ph)</option>
|
||||
<option value="en-za">English (South Africa) (en-za)</option>
|
||||
<option value="en-tt">English (Trinidad & Tobago) (en-tt)</option>
|
||||
<option value="en-gb">English (United Kingdom) (en-gb)</option>
|
||||
<option value="en-us">English (United States) (en-us)</option>
|
||||
<option value="en-zw">English (Zimbabwe) (en-zw)</option>
|
||||
<option value="eo">Esperanto (eo)</option>
|
||||
<option value="et">Estonian (et)</option>
|
||||
<option value="fo">Faeroese (fo)</option>
|
||||
<option value="fa">Farsi (Persian) (fa)</option>
|
||||
<option value="fj">Fijian (fj)</option>
|
||||
<option value="fi">Finnish (fi)</option>
|
||||
<option value="fr">French (Standard) (fr)</option>
|
||||
<option value="fr-be">French (Belgium) (fr-be)</option>
|
||||
<option value="fr-ca">French (Canada) (fr-ca)</option>
|
||||
<option value="fr-fr">French (France) (fr-fr)</option>
|
||||
<option value="fr-lu">French (Luxembourg) (fr-lu)</option>
|
||||
<option value="fr-mc">French (Monaco) (fr-mc)</option>
|
||||
<option value="fr-ch">French (Switzerland) (fr-ch)</option>
|
||||
<option value="fy">Frisian (fy)</option>
|
||||
<option value="fur">Friulian (fur)</option>
|
||||
<option value="gd">Gaelic (Scots) (gd)</option>
|
||||
<option value="gd-ie">Gaelic (Irish) (gd-ie)</option>
|
||||
<option value="gl">Galacian (gl)</option>
|
||||
<option value="ka">Georgian (ka)</option>
|
||||
<option value="de">German (Standard) (de)</option>
|
||||
<option value="de-at">German (Austria) (de-at)</option>
|
||||
<option value="de-de">German (Germany) (de-de)</option>
|
||||
<option value="de-li">German (Liechtenstein) (de-li)</option>
|
||||
<option value="de-lu">German (Luxembourg) (de-lu)</option>
|
||||
<option value="de-ch">German (Switzerland) (de-ch)</option>
|
||||
<option value="el">Greek (el)</option>
|
||||
<option value="gu">Gujurati (gu)</option>
|
||||
<option value="ht">Haitian (ht)</option>
|
||||
<option value="he">Hebrew (he)</option>
|
||||
<option value="hi">Hindi (hi)</option>
|
||||
<option value="hu">Hungarian (hu)</option>
|
||||
<option value="is">Icelandic (is)</option>
|
||||
<option value="id">Indonesian (id)</option>
|
||||
<option value="iu">Inuktitut (iu)</option>
|
||||
<option value="ga">Irish (ga)</option>
|
||||
<option value="it">Italian (Standard) (it)</option>
|
||||
<option value="it-ch">Italian (Switzerland) (it-ch)</option>
|
||||
<option value="ja">Japanese (ja)</option>
|
||||
<option value="kn">Kannada (kn)</option>
|
||||
<option value="ks">Kashmiri (ks)</option>
|
||||
<option value="kk">Kazakh (kk)</option>
|
||||
<option value="km">Khmer (km)</option>
|
||||
<option value="ky">Kirghiz (ky)</option>
|
||||
<option value="tlh">Klingon (tlh)</option>
|
||||
<option value="ko">Korean (ko)</option>
|
||||
<option value="ko-kp">Korean (North Korea) (ko-kp)</option>
|
||||
<option value="ko-kr">Korean (South Korea) (ko-kr)</option>
|
||||
<option value="la">Latin (la)</option>
|
||||
<option value="lv">Latvian (lv)</option>
|
||||
<option value="lt">Lithuanian (lt)</option>
|
||||
<option value="lb">Luxembourgish (lb)</option>
|
||||
<option value="mk">FYRO Macedonian (mk)</option>
|
||||
<option value="ms">Malay (ms)</option>
|
||||
<option value="ml">Malayalam (ml)</option>
|
||||
<option value="mt">Maltese (mt)</option>
|
||||
<option value="mi">Maori (mi)</option>
|
||||
<option value="mr">Marathi (mr)</option>
|
||||
<option value="mo">Moldavian (mo)</option>
|
||||
<option value="nv">Navajo (nv)</option>
|
||||
<option value="ng">Ndonga (ng)</option>
|
||||
<option value="ne">Nepali (ne)</option>
|
||||
<option value="no">Norwegian (no)</option>
|
||||
<option value="nb">Norwegian (Bokmal) (nb)</option>
|
||||
<option value="nn">Norwegian (Nynorsk) (nn)</option>
|
||||
<option value="oc">Occitan (oc)</option>
|
||||
<option value="or">Oriya (or)</option>
|
||||
<option value="om">Oromo (om)</option>
|
||||
<option value="fa-ir">Persian/Iran (fa-ir)</option>
|
||||
<option value="pl">Polish (pl)</option>
|
||||
<option value="pt">Portuguese (pt)</option>
|
||||
<option value="pt-br">Portuguese (Brazil) (pt-br)</option>
|
||||
<option value="pa">Punjabi (pa)</option>
|
||||
<option value="pa-in">Punjabi (India) (pa-in)</option>
|
||||
<option value="pa-pk">Punjabi (Pakistan) (pa-pk)</option>
|
||||
<option value="qu">Quechua (qu)</option>
|
||||
<option value="rm">Rhaeto-Romanic (rm)</option>
|
||||
<option value="ro">Romanian (ro)</option>
|
||||
<option value="ro-mo">Romanian (Moldavia) (ro-mo)</option>
|
||||
<option value="ru">Russian (ru)</option>
|
||||
<option value="ru-mo">Russian (Moldavia) (ru-mo)</option>
|
||||
<option value="sz">Sami (Lappish) (sz)</option>
|
||||
<option value="sg">Sango (sg)</option>
|
||||
<option value="sa">Sanskrit (sa)</option>
|
||||
<option value="sc">Sardinian (sc)</option>
|
||||
<option value="sd">Sindhi (sd)</option>
|
||||
<option value="si">Singhalese (si)</option>
|
||||
<option value="sr">Serbian (sr)</option>
|
||||
<option value="sk">Slovak (sk)</option>
|
||||
<option value="sl">Slovenian (sl)</option>
|
||||
<option value="so">Somani (so)</option>
|
||||
<option value="sb">Sorbian (sb)</option>
|
||||
<option value="es">Spanish (es)</option>
|
||||
<option value="es-ar">Spanish (Argentina) (es-ar)</option>
|
||||
<option value="es-bo">Spanish (Bolivia) (es-bo)</option>
|
||||
<option value="es-cl">Spanish (Chile) (es-cl)</option>
|
||||
<option value="es-co">Spanish (Colombia) (es-co)</option>
|
||||
<option value="es-cr">Spanish (Costa Rica) (es-cr)</option>
|
||||
<option value="es-do">Spanish (Dominican Republic) (es-do)</option>
|
||||
<option value="es-ec">Spanish (Ecuador) (es-ec)</option>
|
||||
<option value="es-sv">Spanish (El Salvador) (es-sv)</option>
|
||||
<option value="es-gt">Spanish (Guatemala) (es-gt)</option>
|
||||
<option value="es-hn">Spanish (Honduras) (es-hn)</option>
|
||||
<option value="es-mx">Spanish (Mexico) (es-mx)</option>
|
||||
<option value="es-ni">Spanish (Nicaragua) (es-ni)</option>
|
||||
<option value="es-pa">Spanish (Panama) (es-pa)</option>
|
||||
<option value="es-py">Spanish (Paraguay) (es-py)</option>
|
||||
<option value="es-pe">Spanish (Peru) (es-pe)</option>
|
||||
<option value="es-pr">Spanish (Puerto Rico) (es-pr)</option>
|
||||
<option value="es-es">Spanish (Spain) (es-es)</option>
|
||||
<option value="es-uy">Spanish (Uruguay) (es-uy)</option>
|
||||
<option value="es-ve">Spanish (Venezuela) (es-ve)</option>
|
||||
<option value="sx">Sutu (sx)</option>
|
||||
<option value="sw">Swahili (sw)</option>
|
||||
<option value="sv">Swedish (sv)</option>
|
||||
<option value="sv-fi">Swedish (Finland) (sv-fi)</option>
|
||||
<option value="sv-sv">Swedish (Sweden) (sv-sv)</option>
|
||||
<option value="ta">Tamil (ta)</option>
|
||||
<option value="tt">Tatar (tt)</option>
|
||||
<option value="te">Teluga (te)</option>
|
||||
<option value="th">Thai (th)</option>
|
||||
<option value="tig">Tigre (tig)</option>
|
||||
<option value="ts">Tsonga (ts)</option>
|
||||
<option value="tn">Tswana (tn)</option>
|
||||
<option value="tr">Turkish (tr)</option>
|
||||
<option value="tk">Turkmen (tk)</option>
|
||||
<option value="uk">Ukrainian (uk)</option>
|
||||
<option value="hsb">Upper Sorbian (hsb)</option>
|
||||
<option value="ur">Urdu (ur)</option>
|
||||
<option value="ve">Venda (ve)</option>
|
||||
<option value="vi">Vietnamese (vi)</option>
|
||||
<option value="vo">Volapuk (vo)</option>
|
||||
<option value="wa">Walloon (wa)</option>
|
||||
<option value="cy">Welsh (cy)</option>
|
||||
<option value="xh">Xhosa (xh)</option>
|
||||
<option value="ji">Yiddish (ji)</option>
|
||||
<option value="zu">Zulu (zu)</option>
|
||||
</select>
|
||||
<input id="searchInput" type="text" placeholder="Search" onchange="onSearchChanged()" onkeyup="onSearchChanged()">
|
||||
<label><input id="showLocCheck" type="checkbox" onchange="onLocChanged()"> Show Location</label>
|
||||
|
@ -544,4 +716,4 @@
|
|||
start();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -3,7 +3,7 @@ You can help translate MeshCentral into other languages pretty easily. In this f
|
|||
|
||||
Download the following Windows tool to open the "translate.json" file and edit strings.
|
||||
|
||||
https://info.meshcentral.com/downloads/MeshCentral2/ResourceTranslator.zip
|
||||
https://meshcentral.com/tools/ResourceTranslator.zip
|
||||
|
||||
Once done, save the file back and run this:
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
@ -674,6 +674,23 @@
|
|||
.night .tagSpan {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#d3serveraction, #d2serveraction {
|
||||
width: 100%;
|
||||
background-color: #d3d9d6;
|
||||
text-align: left;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#d3serverfiles, #d2serverfiles {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
background-color: white;
|
||||
padding: 2px;
|
||||
border: 1px solid gray;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;margin:0;padding:0;border:0;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif">
|
||||
|
@ -927,6 +944,7 @@
|
|||
<span id=DeskChatButton><img src='images/icon-chat.png' onclick=deviceChat(event) height=16 width=16 style=padding-top:5px;cursor:pointer /></span>
|
||||
<span id=DeskToastButton><img src='images/icon-notify.png' onclick=deviceToastFunction() height=16 width=16 style=padding-top:5px;cursor:pointer /></span>
|
||||
<span id=DeskOpenWebButton><img src='images/icon-url2.png' onclick=deviceUrlFunction() height=16 width=16 style=padding-top:5px;cursor:pointer /></span>
|
||||
<span id=DeskRunButton><img src='images/icon-play.png' onclick=runDeviceCmd() height=16 width=16 style=padding-top:2px;cursor:pointer /></span>
|
||||
<!--<input id=DeskToolsButton type=button value=Tools onkeypress="return false" onkeydown="return false" onclick="toggleDeskTools()"> -->
|
||||
</div>
|
||||
<div>
|
||||
|
@ -2570,6 +2588,111 @@
|
|||
go(20);
|
||||
}
|
||||
|
||||
//
|
||||
// FILE SELECTOR, DIALOG 3
|
||||
//
|
||||
|
||||
function d3init() {
|
||||
d3fileoptions = { dialog: 1, filter: 'd3filter', files: 'd3serverfiles', folderup: 'p3FolderUp', currentFolder: 'p3CurrentFolder', func: d3setActions };
|
||||
Q('d3localFile').value = '';
|
||||
Q('d3localFile').accept = Q('d3filter').value;
|
||||
d3modechange();
|
||||
}
|
||||
|
||||
function d3modechange() {
|
||||
var mode = Q('d3uploadMode').value;
|
||||
QV('d3localmode', mode == 1);
|
||||
QV('d3servermode', mode == 2);
|
||||
if (mode == 1) { d3setActions(); } else { d3updatefiles(); }
|
||||
}
|
||||
|
||||
var d3filetreelinkpath;
|
||||
var d3filetreelocation = [];
|
||||
var d3fileoptions = null;
|
||||
function d3updatefiles() {
|
||||
if (d3fileoptions == null) return;
|
||||
if ((d3fileoptions.filter == 'd3filter') && (Q('d3uploadMode').value == 1)) return;
|
||||
var html1 = '', html2 = '', filetreex = filetree, folderdepth = 1, publicPath = null, lastFolderName = '';
|
||||
|
||||
// Navigate to path location, build the paths at the same time
|
||||
var d3filetreelocation2 = [], oldlinkpath = d3filetreelinkpath, checkedBoxes = [], checkboxes = document.getElementsByName('fc');
|
||||
for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { checkedBoxes.push(checkboxes[i].value) }; } // Save all existing checked boxes
|
||||
|
||||
d3filetreelinkpath = '';
|
||||
for (var i in d3filetreelocation) {
|
||||
if ((filetreex.f != null) && (filetreex.f[d3filetreelocation[i]] != null)) {
|
||||
d3filetreelocation2.push(d3filetreelocation[i]);
|
||||
if ((folderdepth == 1)) {
|
||||
var sp = d3filetreelocation[i].split('/');
|
||||
publicPath = window.location + sp[0] + 'files/' + sp[2];
|
||||
if (d3filetreelocation[i] === userinfo._id) { d3filetreelinkpath += 'self'; } else { d3filetreelinkpath += (sp[0] + '/' + sp[2]); }
|
||||
} else {
|
||||
if (d3filetreelinkpath != '') { d3filetreelinkpath += '/' + d3filetreelocation[i]; if (folderdepth > 2) { publicPath += '/' + d3filetreelocation[i]; } }
|
||||
}
|
||||
filetreex = filetreex.f[d3filetreelocation[i]];
|
||||
lastFolderName = filetreex.n;
|
||||
folderdepth++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
d3filetreelocation = d3filetreelocation2; // In case we could not go down the full path, we set the new path location here.
|
||||
|
||||
// Sort the files
|
||||
var filetreexx = p5sort_files(filetreex.f);
|
||||
|
||||
// File filter
|
||||
var fileFilter = '';
|
||||
if (d3fileoptions.filter) { fileFilter = Q(d3fileoptions.filter).value };
|
||||
|
||||
// Display all files and folders at this location
|
||||
for (var i in filetreexx) {
|
||||
// Figure out the name and shortname
|
||||
var f = filetreexx[i], name = f.n, shortname;
|
||||
|
||||
// Filter out files
|
||||
if ((f.t == 3) && (fileFilter != '') && (f.nx.toLowerCase().endsWith(fileFilter) == false)) { continue; }
|
||||
if (name.length > 70) { shortname = '<span title="' + EscapeHtml(name) + '">' + EscapeHtml(name.substring(0, 70)) + ("..." + '</span>'); } else { shortname = EscapeHtml(name); }
|
||||
|
||||
// Figure out the size
|
||||
var fsize = '';
|
||||
if (f.s != null) { fsize = getFileSizeStr(f.s); }
|
||||
|
||||
var h = '';
|
||||
if (f.t != 3) {
|
||||
var title = '';
|
||||
h = '<div class=filelist file=999><span style=float:right title="' + title + '"></span><span><div class=fileIcon' + f.t + ' onclick=d3folderset("' + encodeURIComponentEx(f.nx) + '")></div> <a href=# style=cursor:pointer onclick=\'return d3folderset("' + encodeURIComponentEx(f.nx) + '")\'>' + shortname + '</a></span></div>';
|
||||
} else {
|
||||
var link = shortname;
|
||||
//if (f.s > 0) { link = "<a rel=\"noreferrer noopener\" target=\"_blank\" href=\"downloadfile.ashx?link=" + encodeURIComponentEx(filetreelinkpath + '/' + f.nx) + "\">" + shortname + "</a>"; }
|
||||
h = '<div class=filelist file=3><input style=float:left name=fcx class=fcb type=checkbox onchange=d3setActions() value="' + f.nx + '"> <span style=float:right>' + EscapeHtml(fsize) + '</span><span><div class=fileIcon' + f.t + '></div>' + link + '</span></div>';
|
||||
}
|
||||
|
||||
if (f.t < 3) { html1 += h; } else { html2 += h; }
|
||||
}
|
||||
|
||||
if (d3fileoptions.currentFolder) { QH(d3fileoptions.currentFolder, lastFolderName); }
|
||||
QH(d3fileoptions.files, html1 + html2);
|
||||
QE(d3fileoptions.folderup, d3filetreelocation.length > 0);
|
||||
if (d3fileoptions.func) { d3fileoptions.func(); }
|
||||
}
|
||||
|
||||
function d3folderset(x) { d3filetreelocation.push(decodeURIComponent(x)); d3updatefiles(); return false; }
|
||||
function d3folderup(x) { if (x == null) { d3filetreelocation.pop(); } else { while (d3filetreelocation.length > x) { d3filetreelocation.pop(); } } d3updatefiles(); }
|
||||
function d3getFileSel() { var cc = []; var checkboxes = document.getElementsByName('fcx'); for (var i = 0; i < checkboxes.length; i++) { if (checkboxes[i].checked) { cc.push(checkboxes[i].value) } } return cc; }
|
||||
function d3setActions() {
|
||||
if (d3fileoptions.dialog == 1) {
|
||||
var mode = Q('d3uploadMode').value;
|
||||
if (mode == 1) {
|
||||
QE('idx_dlgOkButton', Q('d3localFile').value.length > 0);
|
||||
} else {
|
||||
QE('idx_dlgOkButton', d3getFileSel().length == 1);
|
||||
}
|
||||
} else if (d3fileoptions.dialog == 2) {
|
||||
QE('idx_dlgOkButton', d3getFileSel().length == 1);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// MY FILES
|
||||
//
|
||||
|
@ -3957,6 +4080,99 @@
|
|||
meshserver.send({ action: 'msg', type: 'openUrl', nodeid: currentNode._id, url: Q('d2devurl').value });
|
||||
}
|
||||
|
||||
function runDeviceCmd(nodeid) { if (xxdialogMode) return; d2runCommandDialog({ nodeids: [ nodeid ? decodeURIComponent(nodeid) : currentNode._id ] }); }
|
||||
|
||||
function d2runCommandDialog(options) {
|
||||
var wintype = false, linuxtype = false, agenttype = false;
|
||||
for (var i in options.nodeids) {
|
||||
var n = getNodeFromId(options.nodeids[i]);
|
||||
if (n.agent) { if ((GetNodeRights(n) & 24) == 24) { agenttype = true; }
|
||||
if ((n.agent.id > 0) && (n.agent.id < 5)) { wintype = true; } else { linuxtype = true; } }
|
||||
}
|
||||
if ((wintype == true) || (linuxtype == true) || (agenttype == true)) {
|
||||
// Fetch run options
|
||||
var runopt = { type:1, runAs:0, source:1, cmd:'' };
|
||||
try { runopt = JSON.parse(getstore('runopt', runopt)); } catch (ex) {}
|
||||
|
||||
if (options.selectedFile) {
|
||||
var filename = options.selectedFile.name.toLowerCase();
|
||||
console.log('filename', filename);
|
||||
if (filename.endsWith('.bat')) { runopt.type = 1; }
|
||||
if (filename.endsWith('.ps1')) { runopt.type = 2; }
|
||||
if (filename.endsWith('.sh')) { runopt.type = 3; }
|
||||
if (filename.endsWith('.agentconsole')) { runopt.type = 4; }
|
||||
}
|
||||
|
||||
var x = '';
|
||||
if (options.title) { x += options.title + '<br />'; }
|
||||
x += '<select id=d2cmdtype onclick=d2runCommandValidate() style=width:100%;margin-bottom:4px;margin-top:4px>';
|
||||
if (wintype == true) { x += '<option value=1' + ((runopt.type == 1)?' selected':'') + '>' + "Windows Command Prompt" + '</option><option value=2' + ((runopt.type == 2)?' selected':'') + '>' + "Windows PowerShell" + '</option>'; }
|
||||
if (linuxtype == true) { x += '<option value=3' + ((runopt.type == 3)?' selected':'') + '>' + "Linux/BSD/macOS Command Shell" + '</option>'; }
|
||||
if (agenttype == true) { x += '<option value=4' + ((runopt.type == 4)?' selected':'') + '>' + "Agent Console" + '</option>'; } // MESHRIGHT_REMOTECONTROL & MESHRIGHT_AGENTCONSOLE are needed
|
||||
x += '</select>';
|
||||
x += '<select id=d2cmduser style=width:100%;margin-bottom:4px><option value=0' + ((runopt.runAs == 0)?' selected':'') + '>' + "Run as agent" + '</option><option value=1' + ((runopt.runAs == 1)?' selected':'') + '>' + "Run as user, agent if no user" + '</option><option value=2' + ((runopt.runAs == 2)?' selected':'') + '>' + "Must run as user" + '</option></select>';
|
||||
if (options.selectedFile == null) {
|
||||
x += '<select id=d2cmdsource onclick=d2runCommandValidate() style=width:100%;margin-bottom:4px><option value=0' + ((runopt.source == 0)?' selected':'') + '>' + "Commands from text box" + '</option><option value=1' + ((runopt.source == 1)?' selected':'') + '>' + "Commands from file" + '</option>';
|
||||
if (userinfo.siteadmin & 8) { x += '<option value=2' + ((runopt.source == 2)?' selected':'') + '>' + "Commands from file on server" + '</option>'; }
|
||||
x += '</select><textarea id=d2runcmd onkeyup=d2runCommandValidate() style=background-color:#fcf3cf;width:100%;height:200px;resize:none;overflow-y:scroll>' + (runopt.cmd ? EscapeHtml(decodeURIComponent(runopt.cmd)) : '') + '</textarea>';
|
||||
x += '<div id=d2runfile style=display:none><input id=d2runfileex type=file onchange=d2runCommandValidate() id=d2localFile name=files onchange=d2runCommandValidate() /></div>';
|
||||
if (userinfo.siteadmin & 8) { x += '<div id=d2runsfile style=display:none><div id=d2serveraction valign=bottom><input type=button id=p2FolderUp disabled="disabled" onclick=d3folderup() value="Up" /> <span id=p2CurrentFolder></span></div><div id=d2serverfiles></div></div>'; }
|
||||
}
|
||||
setDialogMode(2, "Run Commands", 3, d2groupActionFunctionRunCommands, x, options);
|
||||
if (options.selectedFile == null) {
|
||||
Q('d2runcmd').focus();
|
||||
if (userinfo.siteadmin & 8) { d3fileoptions = { dialog: 2, files: 'd2serverfiles', folderup: 'p2FolderUp', currentFolder: 'p2CurrentFolder', func: null }; d3updatefiles(); } // Update the server files
|
||||
}
|
||||
d2runCommandValidate();
|
||||
}
|
||||
}
|
||||
|
||||
function d2runCommandValidate() {
|
||||
QV('d2cmduser', Q('d2cmdtype').value < 4);
|
||||
if (xxdialogTag.selectedFile == null) {
|
||||
QV('d2runcmd', Q('d2cmdsource').value == 0);
|
||||
QV('d2runfile', Q('d2cmdsource').value == 1);
|
||||
QV('d2runsfile', Q('d2cmdsource').value == 2);
|
||||
var ok = false;
|
||||
if (Q('d2cmdsource').value == 0) { if (Q('d2runcmd').value.length > 0) { ok = true; } } // From text box
|
||||
if (Q('d2cmdsource').value == 1) { if (Q('d2runfileex').files.length == 1) { ok = true; } } // From file
|
||||
if (Q('d2cmdsource').value == 2) { ok = false; } // From server file
|
||||
QE('idx_dlgOkButton', ok);
|
||||
} else {
|
||||
QE('idx_dlgOkButton', true);
|
||||
}
|
||||
}
|
||||
|
||||
function d2groupActionFunctionRunCommands(b, options) {
|
||||
var type = 3;
|
||||
try { type = parseInt(Q('d2cmdtype').value); } catch (ex) { }
|
||||
if (options.selectedFile == null) { putstore('runopt', JSON.stringify({ type: type, runAs: parseInt(Q('d2cmduser').value), source: parseInt(Q('d2cmdsource').value), cmd: encodeURIComponent(Q('d2runcmd').value) })); } // Save run options
|
||||
var cmd = { action: 'runcommands', nodeids: options.nodeids, type: type, runAsUser: parseInt(Q('d2cmduser').value) };
|
||||
if (options.selectedFile) {
|
||||
// Drag & drop file
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) { cmd.cmds = e.target.result; meshserver.send(cmd); if (options.func) { options.func(); } }
|
||||
reader.readAsText(options.selectedFile);
|
||||
} else if (Q('d2cmdsource').value == 0) {
|
||||
// From text box
|
||||
cmd.cmds = Q('d2runcmd').value;
|
||||
meshserver.send(cmd);
|
||||
if (options.func) { options.func(); }
|
||||
} else if (Q('d2cmdsource').value == 1) {
|
||||
// From file
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) { cmd.cmds = e.target.result; meshserver.send(cmd); if (options.func) { options.func(); } }
|
||||
reader.readAsText(Q('d2runfileex').files[0]);
|
||||
} else if (Q('d2cmdsource').value == 2) {
|
||||
// From server file
|
||||
var files = d3getFileSel();
|
||||
if (files.length != 1) return;
|
||||
cmd.cmdpath = d3filetreelocation.join('/') + '/' + files[0];
|
||||
meshserver.send(cmd);
|
||||
if (options.func) { options.func(); }
|
||||
}
|
||||
}
|
||||
|
||||
// Look to see if we need to update the device timeline
|
||||
function updateDeviceTimeline() {
|
||||
if ((meshserver.State != 2) || (powerTimelineNode == null) || (powerTimelineUpdate == null) || (currentNode == null) || (currentNode.mtype == 3)) return;
|
||||
|
|
Loading…
Reference in New Issue