Browse Source

Merge branch 'main' into feature/429_iptables6

Jaap Marcus 4 years ago
parent
commit
6ae21220b7
100 changed files with 2663 additions and 454 deletions
  1. 34 0
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 20 0
      .github/ISSUE_TEMPLATE/feature_request.md
  3. 14 0
      .github/ISSUE_TEMPLATE/support-request.md
  4. 260 41
      CHANGELOG.md
  5. 21 61
      CONTRIBUTING.md
  6. 0 25
      ISSUE_TEMPLATE.md
  7. 20 10
      README.md
  8. 6 3
      SECURITY.md
  9. 5 0
      bin/v-acknowledge-user-notification
  10. 51 7
      bin/v-add-backup-host
  11. 4 1
      bin/v-add-cron-hestia-autoupdate
  12. 8 3
      bin/v-add-cron-job
  13. 5 0
      bin/v-add-cron-letsencrypt-job
  14. 9 2
      bin/v-add-cron-reports
  15. 5 0
      bin/v-add-cron-restart-job
  16. 8 2
      bin/v-add-database
  17. 19 9
      bin/v-add-database-host
  18. 85 0
      bin/v-add-database-temp-user
  19. 25 3
      bin/v-add-dns-domain
  20. 8 0
      bin/v-add-dns-on-web-alias
  21. 15 1
      bin/v-add-dns-record
  22. 6 0
      bin/v-add-domain
  23. 133 0
      bin/v-add-fastcgi-cache
  24. 11 0
      bin/v-add-firewall-ban
  25. 11 0
      bin/v-add-firewall-chain
  26. 6 0
      bin/v-add-firewall-ipset
  27. 11 0
      bin/v-add-firewall-rule
  28. 8 1
      bin/v-add-fs-archive
  29. 7 0
      bin/v-add-fs-directory
  30. 7 0
      bin/v-add-fs-file
  31. 104 18
      bin/v-add-letsencrypt-domain
  32. 16 3
      bin/v-add-letsencrypt-host
  33. 8 2
      bin/v-add-letsencrypt-user
  34. 8 2
      bin/v-add-mail-account
  35. 7 1
      bin/v-add-mail-account-alias
  36. 7 1
      bin/v-add-mail-account-autoreply
  37. 11 2
      bin/v-add-mail-account-forward
  38. 8 2
      bin/v-add-mail-account-fwd-only
  39. 30 25
      bin/v-add-mail-domain
  40. 7 1
      bin/v-add-mail-domain-antispam
  41. 7 1
      bin/v-add-mail-domain-antivirus
  42. 7 1
      bin/v-add-mail-domain-catchall
  43. 10 4
      bin/v-add-mail-domain-dkim
  44. 77 0
      bin/v-add-mail-domain-smtp-relay
  45. 6 1
      bin/v-add-mail-domain-ssl
  46. 65 20
      bin/v-add-mail-domain-webmail
  47. 8 0
      bin/v-add-remote-dns-domain
  48. 12 1
      bin/v-add-remote-dns-host
  49. 8 0
      bin/v-add-remote-dns-record
  50. 10 9
      bin/v-add-sys-filemanager
  51. 7 0
      bin/v-add-sys-firewall
  52. 19 5
      bin/v-add-sys-ip
  53. 118 0
      bin/v-add-sys-pma-sso
  54. 9 1
      bin/v-add-sys-quota
  55. 177 0
      bin/v-add-sys-rainloop
  56. 199 0
      bin/v-add-sys-roundcube
  57. 7 0
      bin/v-add-sys-sftp-jail
  58. 63 0
      bin/v-add-sys-smtp-relay
  59. 0 90
      bin/v-add-sys-theme
  60. 19 3
      bin/v-add-user
  61. 5 0
      bin/v-add-user-2fa
  62. 10 2
      bin/v-add-user-composer
  63. 5 1
      bin/v-add-user-notification
  64. 5 2
      bin/v-add-user-package
  65. 8 0
      bin/v-add-user-sftp-jail
  66. 5 0
      bin/v-add-user-sftp-key
  67. 8 3
      bin/v-add-user-ssh-key
  68. 74 0
      bin/v-add-user-wp-cli
  69. 40 10
      bin/v-add-web-domain
  70. 11 4
      bin/v-add-web-domain-alias
  71. 72 0
      bin/v-add-web-domain-allow-users
  72. 7 6
      bin/v-add-web-domain-backend
  73. 7 1
      bin/v-add-web-domain-ftp
  74. 9 2
      bin/v-add-web-domain-httpauth
  75. 8 1
      bin/v-add-web-domain-proxy
  76. 121 0
      bin/v-add-web-domain-redirect
  77. 14 6
      bin/v-add-web-domain-ssl
  78. 13 3
      bin/v-add-web-domain-ssl-force
  79. 11 3
      bin/v-add-web-domain-ssl-hsts
  80. 59 0
      bin/v-add-web-domain-ssl-preset
  81. 8 2
      bin/v-add-web-domain-stats
  82. 9 3
      bin/v-add-web-domain-stats-user
  83. 17 6
      bin/v-add-web-php
  84. 148 10
      bin/v-backup-user
  85. 7 1
      bin/v-backup-users
  86. 6 1
      bin/v-change-cron-job
  87. 7 0
      bin/v-change-database-host-password
  88. 7 0
      bin/v-change-database-owner
  89. 8 2
      bin/v-change-database-password
  90. 8 1
      bin/v-change-database-user
  91. 6 1
      bin/v-change-dns-domain-exp
  92. 9 3
      bin/v-change-dns-domain-ip
  93. 9 3
      bin/v-change-dns-domain-soa
  94. 8 2
      bin/v-change-dns-domain-tpl
  95. 9 3
      bin/v-change-dns-domain-ttl
  96. 8 2
      bin/v-change-dns-record
  97. 8 1
      bin/v-change-dns-record-id
  98. 17 5
      bin/v-change-domain-owner
  99. 7 2
      bin/v-change-firewall-rule
  100. 9 0
      bin/v-change-fs-file-permission

+ 34 - 0
.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,34 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: "[BUG]"
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is. Please include as much information as possible in your issue report, such as the configuration of your server and any troubleshooting steps that you've already performed.
+
+**NOTE: Do not include any personal or sensitive information, such as email addresses or passwords.**
+
+**To Reproduce**
+What steps did you take when the issue occured? 
+1. Ex.: Click on the "Web" tab.
+2. Ex.: Click on "Add Web Domain".
+3. Ex.: Attempted to add a domain and received an Internal Server Error.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Operating system:**
+Please enter your answer here (e.g. Ubuntu 20.04 LTS)
+
+**Hestia Control Panel version:**
+Please enter your answer here (e.g. 1.3.2). 
+
+**Additional context**
+If there is anything else that you'd like us to know about this issue that will help us diagnose and troubleshoot more effectively, such as links to forum posts or other discussions, please feel free to share here.

+ 20 - 0
.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: "[FEATURE]"
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.

+ 14 - 0
.github/ISSUE_TEMPLATE/support-request.md

@@ -0,0 +1,14 @@
+---
+name: Support request
+about: For support, take a look here
+title: "[SUPPORT]"
+labels: ''
+assignees: ''
+
+---
+
+**Please do NOT use our GitHub Project for support requests, you can find community support and help here:**
+
+**Documentation:** [docs.hestiacp.com](https://docs.hestiacp.com/)
+**Forums:** [forum.hestiacp.com](https://forum.hestiacp.com/)
+**Discord:** [Join the discussion](https://discord.gg/8b2HGNe8ne)

+ 260 - 41
CHANGELOG.md

@@ -1,50 +1,269 @@
 # Changelog
 All notable changes to this project will be documented in this file.
 
+## [Development]
+
+### Features
+
+- Include DMARC record in DNS record list #1836
+
+### Bugfixes
+
+- Improve the calculated disk size of a new backup estimated by excluding the exclude folders, mail accounts and database in backups (#1616) @Myself5
+- Improve v-update-firewall / v-stop-firewarewall to make it self healing (#1892) @myrevery 
+- Update phpMyAdmin version to 1.5.1 (See https://www.phpmyadmin.net/news/2021/6/4/phpmyadmin-511-released/)
+- Fixed a bug after rebuilding mail with Exim4 and suspended domains (#1886)
+- Fixed "Allowed IP addresses for API" field with strange behaviour #1866
+- Fixed an issue where the "Saved confirmation" was not set due to a redirect #1879
+- Increased minimal memory requirements for ClamD / ClamAV.  #1840
+- Restore of backup did not rebuild the "Forced SSL" and "HSTS" config on new account #1862
+- Keep changes made by /install/upgrade/manual/install_awstats_geopip.sh on update HestiaCP (via Discord)
+
+## [1.4.2] - Service release
+
+- **NOTE:** During the 1.4.1 / 1.4.0 release we have introduced a bug for Ubuntu 20.04 and 18.04 users with multiple network ports on the server. This release will solve the problems caused by this bug! If you are unable to download the Hestia packages via apt. Run the following command via CLI or SSH as root
+
+```
+    iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
+```
+
+Then run the update via 
+
+```
+    apt update && apt upgrade
+```
+
+### Bugfixes
+
+- Fix issue wit startup script for iptables / network (#1849) (@myrevery)
+- Fix problem with accidentally replacing nginx.conf during upgrade nginx (#1878 / @myrevery)
+- Fix issue with installing Ubuntu 18.04
+- Fix issue with login into file manger as admin user
+- Added proxy_extentions back to support older custom templates
+- Added the possibility to skip the forced reboot when interactive is set to no
+- Fixed an issue with modx template
+- Updated translations (Croatian, Czech and Italian)  
+- Fixed an issue where users where not able to save / update web domains when POLICY_USER_EDIT_WEB_TEMPLATES is enabled (#1872)
+- Fixed an issue where admin users where not able to add new ssh key for users (#1870)
+- Fixed an issue where domain.com was not affected as a valid domain (#1874)
+- Fixed an issue where "development" icon was not removed on update to release (#1835)
+  
+## [1.4.1] - Bug fix
+
+- Fixed bug with 2FA enabled logins 
+
+## [1.4.0] - Major Release (Feature / Quality Update)
+
+- **NOTE:** Ubuntu 16.04 (Xenial) is no longer supported as it has reached EOL (end-of-life) status. 
+- **NOTE:** Apache in "standalone" mode is no longer actively supported and has been removed from installer options. Nginx (Proxy) + Apache2 will remain supported. 
+- **NOTE:** Custom "quick installer apps" will not work anymore due to changes in how we handle quick installer apps. Minimal changes to the Quick installer apps are required! Please check https://github.com/hestiacp/hestia-quick-install for how to migrate!
+- **NOTE:** Manual upgrade scripts are available to update Roundcube, Rainloop and PHPmyadmin to the last version they can be found in /usr/local/hestia/install/upgrade/manual/
+
+### Features
+- Introduced support for NGINX FastCGI cache.
+- Introduced support for SMTP Relay / smarthosts (server-wide or per-domain).
+- Introduced the ability to choose which webmail client to use per-domain (Roundcube or Rainloop).
+- Added support for Rainloop (Run v-add-sys-rainloop to install it)
+- Added B2 Backup Support for Remote Backup Location - thanks **@rez0n**!
+- Added template support for osTicket - thanks **@madito**!
+- Packages for phpMyAdmin, Roundcube, and Rainloop will be pulled directly from their upstream source instead of APT for new installations.
+- Added DNS records view to mail domains which provides DKIM, SPF, and other entries to use with an external provider.
+- Added an upgrade script to provide in-place upgrades to php7.4 (or any other version).
+- Added Drupal and Nextcloud quick installer support (Removed placeholder Joomla)
+- Added a new optional theme "Vestia"
+- Added a switch to disable the API and also limit the api by default to 127.0.0.1 only. For current installs added the option "allow-all" on default 
+- After first reboot of Hestia will try do 1 attempt to request / generate a valid Lets encrypt certificate
+- Introduced multiple new security policies via WebUI. 
+    - Allow users to edit Web / Proxy / DNS / Backend templates
+    - Allow users to edit account details
+    - Allow suspended users to login with "read-only" access
+    - Allow users view / delete user history
+    - Enforce sub domain ownership
+    - Limit access to admin account when other users have the role "Administrator" assigned to them.
+- Disable user to login via WebUI / Limit access to WebUI to certain IP address per user. 
+- Discourage websites to be created under "admin" account and redirect users to create new users. 
+- Added support for redirecting to www / non www domains (or custom)  #427 / #1638.
+- Allow users to see failed login attempts on there account. 
+- Introduced support for ARM based systems. Currently the packages are not available via ATP! 
+- Force reboot of system after install
+
+### Bugfixes
+- Fixed an issue where user name was duplicated when editing FTP users. (#1411)
+- Fixed an issue where the iptables service would appear to be in a stopped state when fail2ban is stopped. (#1374)
+- Fixed an issue where the default language value was incorrectly set under Server Settings > Configure.
+- Fixed an issue with the dark theme where available updates were incorrectly displayed.
+- Fixed an issue where local and FTP backup files were not deleted when running `v-delete-user-backup`. (#1421)
+- Fixed an issue where IP addresses could not be deleted. (#1423)
+- Fixed an issue where `v-rebuild-user` would incorrectly rebuild domain items in addition to user account configuration.
+- Fixed an issue which caused a web domain's custom document root value to be lost when restoring from backup.
+- Fixed an issue which caused a `NSPOSIXErrorDomain:100` error when using Safari/iOS (thanks **@stsimb**).
+- Fixed an issue where exim ignored the configured mail quota limit.
+- Fixed an issue where invalid character validation was performed when editing mail auto replies.
+- Fixed an issue which caused Let's Encrypt to fail when using the Moodle template (thanks **@ArturoBlanco**).
+- Fixed an issue where the MySQL `wait_timeout` value was not saved due to wrong regexp attribute (thanks **@guicapanema**).
+- Fixed an issue where nginx web statistics authorization file was placed in the wrong directory.
+- Fixed several small issues that were reported when using PostgreSQL.
+- Improved reliability of mail domains and webmail clients.
+- Improved reliability of service restarts during upgrades.
+- Improved compatibility with Blesta / WHMCS plugins.
+- Improved API error handling routines - thanks **@danielalexis**!
+- Improved backup performance through the use of multi-threading when creating archives using the `zstd` compression type.
+- Improved error handling when creating firewall rules.
+- Improved handling of suspended users and domains to allow deletion without unsuspension.
+- Improved dependencies over package control to install `lsb-release` and `zstd`.
+- Improved SFTP connection handling to be case insensitive (thanks **@lazzurs**).
+- Improved domain validation to prevent creating subdomains when the top-level domain belongs to another account (thanks **@KuJoe** and **@sickcodes**).
+- Improved IDN domain handling to resolve issues with Let's Encrypt SSL and mail domain services.
+- Added private folder to openbasedir permissions for all main templates.
+- Disabled changing backup folder via Web UI because it used symbolic link instead of mount causing issues with restore mail / user files.
+- Fixed XSS vulnerability in `v-add-sys-ip` and user history log (thanks **@numanturle**).
+- Fixed remote code execution vulnerability which could occur when deleting SSH keys (thanks **@numanturle**).
+- Fixed vulnerability in v-update-sys-hestia (thanks **@numanturle**)
+- Disabled the Update via WebUI due to timeout issues. Please update via ```apt update && apt upgrade``` in command line instead.
+- Improve how Quick install of web apps are handled and allow users added apps to be maintained in list view. 
+- Fixed an issue where the api was enabled after an update of HestiaCP
+- Fixed an issue when the default php version got deleted webmail didn't work any more. #1477
+- Limit access when "demo" mode is enabled. 
+- Fixed an issue where limitations on aliases didn't work propperly
+- Fixed an issue where "Exit to control pannel" link got changed to "Logout" #1669
+- Allow packages to be deleted when in use. Current users are changed to "Default" package. 
+- Fixed multiple bugs with in v-restore-users
+- Redesign statics page
+- Allow self signed certificates to be created with aliases. 
+- Fixed issue where mail accounts where sorting incorrectly by size #1687
+- Improve results v-search-command #1703
+- Merge Codeiginiter / Drupal templates. 
+- Prepare template for FastCGI support an improve security by allowing only .well-known for Let's encrypt requests
+- Update Cloudflare Ips in nginx.conf
+- Fixed an issue where emails where send to nobody when connection failed to database #1765
+- Fixed an issue where no notifications where send on failure and save local backup if remote backup failed. 
+- Fixed an issue where domains containing 2 dots in the top level domain could accidentally got removed #1763
+- Fixed an issue where www could be created and after delete webmail doesn't work anymore #1746
+- Standardize headers for upgrade scripts
+- Improved how we handle custom themes
+- Refactored HMTL / PHP code WebUI
+- Updated ClamAV configuration
+- Fixed issue where file manger key got the wrong permissions
+- Update version Laveral @mariojgt
+
+## [1.3.5] - Service Release
+### Features
+- No new features have been introduced in this release.
+
+### Bugfixes
+- Updated APT repository key for PHP from packages.sury.org (https://forum.hestiacp.com/t/apt-upgrade-failed-gpg-error-packages-sury-org)
+- Updated phpMyAdmin to v5.1.0.
+
+## [1.3.4] - Service Release
+### Features
+- No new features have been introduced in this release.
+
+### Bugfixes
+- Fixed xss vulnerability in v-add-sys-ip and user history log (thanks **@numanturle**)
+- Fixed remote execution possibility when deleting ssh key (thanks **@numanturle**)
+
+## [1.3.3] - Service Release
+### Bugfixes
+- Improved if web folder already exists and do not follow symlink on chmod (thanks @0xGsch and @kikoas1995).
+- Improved api key authentification to prevent brute force attacks.
+- Improved ssh keys folder permission to prevent unauthorized access.
+
+## [1.3.2] - Service Release
+### Features
+- Added PHP v8.0 support for multiphp environment.
+
+### Bugfixes
+- Improved session token handling in login as function, thanks to Vulnerability Laboratory - [Evolution Security GmbH]™.
+- Fixed an where fpm pool config was not deleted when changing backend template.
+- Improved bats testing with multiphp (5.6-8.0) tests.
+- Fixed an issue where full webmail path was loaded as default value.
+
+## [1.3.1] - Service Release
+### Features
+- No new features have been introduced in this release.
+
+### Bugfixes
+- Fixed an issue where updates for `hestia-php` were incorrectly being marked as out-of-date in the UI due to a change in our servicing and package versioning scheme.
+- Fixed an issue that occured on the Updates page where the table row color of available updates would be difficult to read.
+- Fixed an issue where an administrator would get stuck in a loop trying to navigate back after adding a SSH key.
+- Fixed an issue where long table entries which exceeded the table length would overlap other UI elements.
+- Fixed an issue where the total amount of items on a page would fail to display correctly.
+- Improved the accuracy and reliability of tooltips throughout the the Control Panel UI:
+    - Removed unnecessary tooltips from buttons and other elements.
+    - Fixed incorrect tags which prevented tooltips from being displayed.
+    - Introduced tooltips to counter items on the Users, Packages, and Statistics pages to help better distinguish statistics.
+- Improved the display of items, quotas, and suspended items in the Control Panel navigation header - thanks **@cmstew**!
+- Fixed an issue which caused higher than normal CPU usage during an upgrade due to a duplicate condition in the rebuild process.
+- Fixed minor spelling inconsistencies in command line script comments and output text.
+- Fixed an issue where old configuration files were not cleaned up when moving domains with `v-change-domain-owner`.
+- Fixed an issue where a `no backend template doesn't exist` could potentially would appear after upgrade with older templates (#1322).
+- Introduced caching templates for nginx + php-fpm configurations  - thanks **@cmstew**!
+- Fixed an issue where DNS cluster updates could fail due to the format of a DKIM record in an available zone - thanks **@jrohde**!
+- Improved the quality of comment formatting in command line scripts - thanks **@bisubus**! 
+- Fixed an issue where the logo was not displayed in the File Manager - thanks **@robothemes**!
+- Fixed an issue in the Control Panel UI which caused databases and additional FTP accounts to be named incorrectly if manually prefaced with the username.
+- Fixed an issue where custom document roots were not saved correctly.
+- Improved the visibility of service availability in the Control Panel UI.
+- Fixed an issue which let you unsuspend a cronjob on active demo mode.
+- Updated DE, EN, ES, KO, NL and TR languages, thanks to @Wibol, Blackjack, @emrahkayihan, areo and @hahagu!
+- Fixed an issue which let the auto compiler fail with local src builds.
+- Added turkish language to system installers, thanks to @emrahkayihan!
+- Fixed incorrect error message when using unknown domain with v-delete-domain.
+
 ## [1.3.0] - Major Release (Feature / Quality Update)
 ### Features
-- Users can now choose to point a domain to a different document root (similar to domain parking).
-- The software update procedure will now perform a system health check prior to installation and repair missing environment variables.
+- Users can now choose to point a domain to a different document root location (similar to domain parking).
+- The software update process will now perform a system health check before proceeding with installation.
 - Administrators now have control over software update notifications through the following settings in `$HESTIA/conf/hestia.conf` and through the Control Panel web interface:
-    - `UPGRADE_SEND_EMAIL` = Sends an email notification to admin email address
-    - `UPGRADE_SEND_EMAIL_LOG` = Sends installation log output to admin email address
-- Upgrade process will now save logs to the `hst_backups` directory.
-- Support for removing backup remote location (#1083).
-- Add support Proftpd TLS Support
-- Add the possibility to assign user "Administrators" rights on login. Replaces "root" login. Notifications are only send towards the "admin" account email.
-- Updated translations system with the use of Gettext. Modified / Updated all translated strings.
-- Use php7.4 as default version.
-- Updated MariaDB to 10.5 (Manual upgrade required install/upgrade/manual/upgrade_mariadb.sh).
-- Added support for Turkish (emrahk [Forum](https://forum.hestiacp.com/t/how-to-contribute-with-translations/1664/4?u=eris) )
-
-## Bugfixes
-- Removed root login (root / root password )
-- Update apache2.conf replace Include with IncludeOptional (#1072)
-- Add ca-certificates, software-properties-common to the dependencies (#1073 + [Forum](https://forum.hestiacp.com/t/hestiscp-fails-on-new-debian-9-vps/1623/8) ) @daniel-eder
-- Fixed issues with database port during backup when port was missing (#1068)
-- Postqresql: forbid the use of upper case (#1084) causing issues with backup / creating database or user
-- Fixed permissions email account during restore (#1114)
-- Create .npm on creating new user (#1113) @hahagu 
-- Fixed Access to a website without a ssl certificate on https shows the content of the first, valid ssl website (#1103)
-- Fixed an issue when installing --with-debs and version check (#1110)
-- Improved Translations Chinese @myrevery
-- File manager create directory with proper permissions 
-- Removed loop ad v-rebuild-all (#1096)
-- Add $restart flag to v-add-web-domain-backend call (#1094) (#797) @bright-soft
-- Fixed an issue with Restore Failed on Domains with Mail Setups using SSL (#1069)
-- Fixed an issue with PHPMyAdmin button (#1078)
-- Changed WordPress name in Webapp installer (#1074)
-- Add a free disk space validation during backup routine (#1115)
-- Removed PHP validation SSH keys allowing support other types then RSA / DSA
-- Fixed an issue which cause wrong password generation (#1184)
-- Fixed issue with v-add-sys-ip and saving the ip configuration to correct port (@madito)
-- Updated Exim black list for extensions (@kpapad904 / #1138)
-- Fixed multiple bugs due to translations 
-- Fixed bug with passwords containing "'" [Forum](https://forum.hestiacp.com/t/two-factor-authentication-issue-with-standard-user/1652/)
-- Refactor LXD  Complier script
-- Set default theme to "Dark"
-- Clean up gmail.tpl (DNS) (@madito)
-- Improved translations (NL, DE, UK, RU, ES, IT, ZH-CN)
+    - `UPGRADE_SEND_EMAIL` = Sends an email notification to primary admin account's email address
+    - `UPGRADE_SEND_EMAIL_LOG` = Sends installation log output to the primary admin account's email address
+- The upgrade process will now save installation logs to the `/root/hst_backups` directory by default for post-install troubleshooting.
+    - **Note:** We may adjust this path in the future and will document such changes as they happen.
+- We've introduced the ability to assign Administrator rights to other user accounts, enabling them to perform tasks under the Server Settings tab.
+- We've introduced a more robust translation system which will allow us to provide higher quality translations in future releases.
+    - **Note:** Some country codes have been updated, as a result your language setting may default back to English after upgrading.
+- For new installations, MariaDB 10.5 is now the default version.
+    - For existing installations, we've provided a manual post-install upgrade script. Please run `$HESTIA/install/upgrade/manual/upgrade_mariadb.sh` to migrate to MariaDB 10.5).
+- The user interface theme has been set to "Dark" by default. This can be changed from **Server Settings > Configure > Basic Options > Appearance**.
+    - **Note:** The name of the default theme has not been adjusted, and the change to the "dark" theme only applies to new installations at this time. This behavior may be changed in a future release.
+
+### Bugfixes
+- Fixed a security issue where user password reset keys could potentially be gleaned from system process list - thanks **RACK911 LABS**
+- Fixed an issue with passwords containing "`'`" - [Forum](https://forum.hestiacp.com/t/two-factor-authentication-issue-with-standard-user/1652/)
+- Fixed an issue with database backups when the port was not specified (#1068)
+- Fixed an issue where websites without SSL enabled would display the content of the first valid SSL enabled website (#1103)
+- Fixed an issue that would occur when using the `--with-debs` flag with the installer due to an incorrect version check routine (#1110)
+- Fixed an issue with incorrect permissions which would occur when restoring email accounts (#1114)
+- Fixed an issue where the File Manager would apply the wrong permissions on new directories
+- Fixed an issue that prevented successful restoration of SSL-enabled mail domains from a backup archive (#1069)
+- Fixed an issue where the phpMyAdmin button would not work in the Control Panel Web UI (#1078)
+- Fixed an issue where passwords were generated incorrectly (#1184)
+- Fixed an issue in `v-add-sys-ip` to ensure IP configuration is set to the correct port - thanks **@madito**
+- Fixed an issue that resulted in an extended loop condition when running `v-rebuild-all`
+- Improved support for API key usage with the `v-add-remote-dns-host` command (#1265)
+- Improved validation of free disk space when executing backup routine (#1115)
+- Improved support for SSH key types other than RSA / DSA
+- Improved reliability of backup function when removing remote locations (#1083)
+- Improved spam filtering by adding additional known-dangerous file extensions in exim's blacklist (#1138) - thanks **@kpapad904**
+- Updated Apache2 configuration to use Include with IncludeOptional (#1072)
+- Removed the ability to log in as "root" (whic logged to the admin account, deemed no longer necessary)
+- Add ca-certificates, software-properties-common to the dependencies (#1073 + [Forum](https://forum.hestiacp.com/t/hestiscp-fails-on-new-debian-9-vps/1623/8)) - thanks **@daniel-eder**
+- Create .npm directory by default when creating new user accounts (#1113) - thanks **@hahagu** 
+- Improved accuracy of several UI translations (NL, DE, UK, RU, ES, IT, ZH-CN) - thanks **@myrevery** and other contributors for your work!
+- Added `$restart` flag to `v-add-web-domain-backend` command (#1094) (#797) - thanks **@bright-soft**
+- PostgreSQL: forbid the use of upper case (#1084) causing issues with backup / creating database or user
+- Changed WordPress name in Quick Web App installer (#1074)
+- Cleaned up entries used in the Google / Gmail DNS template - thanks **@madito**
+- Enhanced ProFTPd support for TLS
+- Refactored LXD compiler script
+- Updated phpMyAdmin to version 5.0.4
+
+## [1.2.4] - Service Release
+### Features
+- No new features have been introduced in this release.
+
+### Bugfixes
+- Fixes an issue on auto renewing let's encrypt certificates.
 
 ## [1.2.3] - Service Release
 ### Features

+ 21 - 61
CONTRIBUTING.md

@@ -4,16 +4,16 @@ Hestia Control Panel - Contribution Guidelines
 Ways to contribute
 -----------------------
 - **Beta testing**:
-    - Download and install builds from the `beta` branch. Provide feedback to our developers and file any issues that you come across on [GitHub](https://www.github.com/hestiacp/hestiacp/issues).<br>
+    - Download and install builds from the `beta` branch. If you encounter an issue with a beta build, file an issue report on [GitHub](https://www.github.com/hestiacp/hestiacp/issues).<br>
     `v-update-sys-hestia-git hestiacp beta install` will install the latest beta build from our GitHub repository.
 - **Code review and bug fixes**:
-    - Read over the code and if you notice errors (even spelling mistakes), submit a pull request with your fixes.
+    - Read over the code and if you notice errors (even spelling mistakes), submit a pull request with your changes.
 - **New features**:
-    - Is there an awesome feature that you'd love to see included? While our development team tries to fulfill all reasonable requests, it can take time to implement new features depending on the amount of work involved. Submit a pull request with your code and if your idea is approved, we'll review and test it for inclusion with an upcoming release.
+    - Is there an awesome feature that you'd love to see included? Submit a pull request with your changes, and if approved your PR will be reviewed and merged for inclusion in an upcoming release. While our development team tries to accomodate all reasonable requests please remember that it does take time to develop, implement and test new features and as such we may not be able to fulfill all requests or may have to put a feature on backlog for a later date. 
 - **Translations**:
-    - If you are a non-English speaker and would like to improve the quality of the translations used in Hestia Control Panel's web interface, Please go to [Hestia Translate](https://translate.hestiacp.com/projects/hestiacp/) to review the translations. For more information please read [How to contribute with Translations](https://forum.hestiacp.com/t/how-to-contribute-with-translations/1664).  Or open an issue report [GitHub](https://www.github.com/hestiacp/hestiacp/issues) highlighting the issue with the current translation so that it can be corrected.
+    - If you are a non-English speaker and would like to improve the quality of the translations used in Hestia Control Panel's web interface, please go to [Hestia Translate](https://translate.hestiacp.com/projects/hestiacp/) to review the translations database. For more information please read [How to contribute with Translations](https://forum.hestiacp.com/t/how-to-contribute-with-translations/1664) on our forum.  You can also open an issue report [GitHub](https://www.github.com/hestiacp/hestiacp/issues) highlighting the issue with the current translation so that it can be corrected.
 - **Donations**:
-    - If you're not a developer but you still want to make a contribution, you can make a donation to the Hestia Control Panel project to further its development (or if you'd just like to buy our developers a lunch, we'd appreciate that too). We currently accept donations through [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ST87LQH2CHGLA).
+    - If you're not a developer but you still want to make a contribution to support Hestia Control Panel and our developers, you can make a donation to the Hestia Control Panel project to further its development (or if you'd just like to buy our developers a lunch, we'd appreciate that too). We currently accept donations through [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ST87LQH2CHGLA).
 
 Development Guidelines
 -----------------------
@@ -25,78 +25,38 @@ Development for this project takes place in branches to effectively develop, man
 
 We have three primary or "evergreen" branches, which exist throughout our product's lifetime. Please refer to the following table for a description:
 
-| Branch        | Description     | Cycle           |
-|---------------|:---------------:|:---------------:|
-| `main`        | Contains a snapshot of the latest development code.<br>**Not intended for production use and may be unstable.** | Daily  |
-| `beta`        | Contains a snapshot of the next version which is currently in testing.<br>**Not intended for production but should be highly stable.**  | Weekly |
-| `release`     | Contains a snapshot of the latest stable release.<br>**Intended for production use. Same code as packages in repository.** | Monthly |
+| Branch        | Description     
+|---------------|:---------------:|
+| `main`        | Contains a snapshot of the latest development code.<br>**Not intended for production use and contains code from a merge snapshot.**
+| `beta`        | Contains a snapshot of the next version which is currently in testing.<br>**Not intended for production use, however code from this branch should be stable.**
+| `release`     | Contains a snapshot of the latest stable release.<br>**Intended for production use. This repository contains the same code as our compiled packages.**
 
 ### Creating a new branch and submitting pull requests
-The first step is to create a fork of the `hestiacp/hestiacp` repository under your account so that you may submit pull requests and patches via GitHub. 
+The first step is to create a fork of the `hestiacp/hestiacp` repository under your GitHub account so that you may submit pull requests and patches.
 
-Once you've created your fork, clone the repository to your computer and make sure that you've checked out the `main` branch. **Always** create a new topic branch for you work. When submitting pull requests it is important that you target the correct branch to ensure that your changes are properly integrated and tested based on our release schedule. When creating a new branch, we ask that you please adhere to the following naming conventions as much as possible:
+Once you've created your fork, clone the repository to your computer and make sure that you've checked out the `main` branch. **Always** create a new topic branch for your work.
 
 ### Branch naming convention:
-- **Prefix:** `topic/` (such as **bugfix**, **feature**, **refactor**, etc.)
-- **ID**: `888` (GitHub Issue ID if an issue exists) -or- `2020-07` (Year-Month if an issue does not already exist)
-- **Separator:** `_` (underscore)
+- **Prefix:** `topic/` (such as **fix**, **feature**, **refactor**, etc.)
+- **ID**: `888` (GitHub Issue ID if an issue exists)
 - **Title:** `my-awesome-patch`
 
 Branch name examples:
-* `feature/777_my-awesome-new-feature` or `feature/2020-07_my-other-new-feature`
-* `fix/000_some-bug-fix` or `fix/2020-07_this-feature-is-broken`
-* `refactor/2020-07_v-change-domain-owner`
-* `test/2020-07_mail-domain-ssl`
+* `feature/777-my-awesome-new-feature` or `feature/my-other-new-feature`
+* `fix/000-some-bug-fix` or `fix/this-feature-is-broken`
+* `refactor/v-change-domain-owner`
+* `test/mail-domain-ssl`
 
 ### Squashing commits for smaller changes
-When submitting a pull request with multiple smaller commits which are related to the same file or issue, we ask that you please **squash your commits** whenever appropriate in order to keep the project's commit history clean and easy to follow for other developers.
+To aid other developers and keep the project's commit history clean, please **squash your commits** when it's appropriate. For example with smaller commits related to the same piece of code, such as commits labelled "Fixed item 1", "Adjusted color of button XYZ", "Adjusted alignment of button XYZ" can be squashed into one commit with the title "Fixed button issues in item". 
 
 ### What happens when I submit a pull request?
 - Our internal development team will review your work and validate your request.
 - Your changes will be tested to ensure that there are no issues.
 - If changes need to be made, you will be notified via GitHub.
-- Once approved, your code will be merged to the appropriate `staging/*` branch based on the chart below:
-
-All pull requests must include a brief but descriptive title, and a description of the changes that you've made with as much detail as possible. **Only include commits that are related to your feature, bug fix, or patch in your pull request.**
-
-| Topic branches:              | Primary Target:             | Final destination:                    | 
-| -----------------------------|:---------------------------:|:-------------------------------------:|
-| **`feature/*`**              | `staging/features`          | `main`                                |
-| **`fix/*`**                  | `staging/fixes`             | `main` **and** `beta` *or* `release`  |
-| **`refactor/*`**             | `staging/refactoring`       | `main`                                |
-| **`test/*`**                 | `staging/tests`             | `main`                                |
-| **`doc/*`**                  | `staging/docs`              | `main`, `beta`, *or* `release`        |
-
-Our development and release cycles
------------------------
-### During the development cycle:
-- `topic/*` branches are submitted to our team via a pull request. Your changes will be reviewed and tested, and if all appropriate quality assurance checks pass the branch will be merged to the corresponding `staging/*` branch.
-
-- `staging/*` branches merge into `main` at various intervals throughout the development process.
-
-- When all planned features and fixes have been merged to `main`, the code is tested for regressions and bugs.
-
-- A snapshot of `main` is pushed to a temporary branch called `staging/refactoring`, and final code review, refactoring, and optimization takes place. Once complete, `staging/refactoring` merges back to `main` bringing the codebase up-to-date. All other `staging/*` branches synchronize with `main` at this time.
-
-- After final validation checks pass, our development team signs off on the release and the code is pushed from `main` to `beta`.
-
-### During the release cycle:
-- **What happens when code moves from `main` to `beta`**:<br>
-    - **No new feature requests will be approved**.
-    - `main` will receive an increment in it's version number signaling the start of a new development cycle.
-    - `fix/*` topic branches/commits will be cherry picked to `beta` as necessary.
-    - `staging/docs` will merge into `beta` prior to the code being pushed to `release` to bring documentation and supporting files up-to-date.
-
-- If all quality assurance checks pass, our development team will then:
-    - Sign off on the code in `beta`.
-    - Push the code to the `release` branch and create a corresponding version tag.
-    - Compile new packages and publish them to our APT repository. 
-    - **Notes:**
-        - `release` always contains the highest released version of Hestia Control Panel.
-        - For major releases, a `release/vX.x` branch will be created for maintenance and servicing purposes.
-
-
+- Once approved, your code will be merged for inclusion in an upcoming release of Hestia Control Panel.
 
+All pull requests must include a brief but descriptive title, and a detailed description of the changes that you've made. **Only include commits that are related to your feature, bug fix, or patch in your pull request!**
 
 Thank you!
 -----------------------

+ 0 - 25
ISSUE_TEMPLATE.md

@@ -1,25 +0,0 @@
-**Please include as much information as possible in your issue report, such as the configuration of your server and any troubleshooting steps that you've already performed.**
-
-**NOTE: Do not include any personal or sensitive information, such as email addresses or passwords.**
-
-===
-
-### In a few words, please describe the issue that you're experiencing:
-Please enter your answer here (e.g. When I try adding a web domain, an error message appeared stating that the php-fpm pool did not exist).
-
-### What steps did you take when the issue occured? 
-1. Ex.: Click on the Web tab
-2. Ex.: Click on Add Web Domain
-3. Ex.: Attempted to add a domain and received an Internal Server Error.
-
-### Expected behavior:
-Please enter your answer here (e.g. the web domain should have been added successfully).
-
-### Operating system:
-Please enter your answer here (e.g. Ubuntu 20.04 LTS)
-
-### Hestia Control Panel version:
-Please enter your answer here (e.g. 1.2.0). 
-
-### Additional notes:
-If there is anything else that you'd like us to know about this issue, feel free to share here.

+ 20 - 10
README.md

@@ -2,12 +2,12 @@
 
 [Hestia Control Panel](https://www.hestiacp.com/)
 ==================================================
-**Latest stable release:** Version 1.2.4 | [View Changelog](https://github.com/hestiacp/hestiacp/blob/release/CHANGELOG.md)<br>
+**Latest stable release:** Version 1.4.2 | [View Changelog](https://github.com/hestiacp/hestiacp/blob/release/CHANGELOG.md)<br>
 
 **Web:** [www.hestiacp.com](https://www.hestiacp.com/)<br>
 **Documentation:** [docs.hestiacp.com](https://docs.hestiacp.com/)<br>
 **Forums:** [forum.hestiacp.com](https://forum.hestiacp.com/)<br>
-**Discord:** [Join HestiaCP Discord channel](https://discord.gg/nXRUZch)<br />
+**Discord:** [Join the discussion](https://discord.gg/nXRUZch)<br />
 <br>
 [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ST87LQH2CHGLA)
 <br>
@@ -19,17 +19,18 @@ Hestia Control Panel is designed to provide administrators an easy to use web an
 Features and Services
 ----------------------------
 * Apache2 and NGINX with PHP-FPM
-* Multiple PHP versions (5.6 - 7.4, 7.3 as default for optimal compatibility)
+* Multiple PHP versions (5.6 - 8.0, 7.4 as default)
 * DNS Server (Bind) with clustering capabilities
-* POP/IMAP/SMTP mail services with Anti-Virus, Anti-Spam, and Webmail (ClamAV, SpamAssassin, and Roundcube)
+* POP/IMAP/SMTP mail services with Anti-Virus, Anti-Spam, and Webmail (ClamAV, SpamAssassin, Roundcube, Rainloop)
 * MariaDB or PostgreSQL databases
 * Let's Encrypt SSL support with wildcard certificates
 * Firewall with brute-force attack detection and IP lists (iptables, fail2ban, and ipset).
 
-Supported operating systems
+Supported platforms and operating systems
 ----------------------------
-* Debian 10, 9
-* Ubuntu 20.04 LTS, 18.04 LTS, or 16.04 LTS
+* **CPU Architecture:** AMD64 (x86_64 Intel/AMD)
+* **Debian:** 10 or 9
+* **Ubuntu:** 20.04 LTS or 18.04 LTS
 * **NOTE:** Hestia Control Panel must be installed on top of a fresh operating system installation to ensure proper functionality.
 
 Installing Hestia Control Panel
@@ -65,11 +66,20 @@ bash hst-install.sh -h
 ```
 Alternatively, @gabizz has made available a command-line script generator at https://gabizz.github.io/hestiacp-scriptline-generator/ which allows you to easily generate the installation command via GUI.
 
-Issues
+How to upgrade an existing installation
+============================
+Automatic Updates are enabled by default on new installations of Hestia Control Panel and can be managed from **Server Settings > Updates**. To manually check for and install available updates, use the apt package manager:
+```bash
+apt-get update
+apt-get upgrade
+```
+
+Issues & Support Requests
 =============================
-If you've run into a problem, [file a new issue report via GitHub](https://github.com/hestiacp/hestiacp/issues) so that we may investigate further.
+* If you encounter a general problem while using Hestia Control Panel and need help, please [visit our forum](https://forum.hestiacp.com/) to search for potential solutions or post a new thread where community members can assist.
+* Bugs and other reproducible issues should be filed via GitHub by [creating a new issue report](https://github.com/hestiacp/hestiacp/issues) so that our developers can investigate further. Please note that requests for support will be redirected to our forum.
 
-**We cannot provide support for requests that do not describe the troubleshooting steps that have already been performed, or for third-party applications which do not relate to Hestia Control Panel. Please make sure that you fill in the necessary details in your issue reports!**
+**IMPORTANT: We _cannot_ provide support for requests that do not describe the troubleshooting steps that have already been performed, or for third-party applications not related to Hestia Control Panel (such as WordPress). Please make sure that you include as much information as possible in your forum posts or issue reports!**
 
 Contributions
 =============================

+ 6 - 3
SECURITY.md

@@ -2,6 +2,9 @@
 
 ## Reporting a Vulnerability
 
-If you have discovered a vulnerability in Hestia Control Panel,
-let our development team know via e-mail at [email protected] and
-we will respond as soon as possible.
+If you believe that you have have discovered a vulnerability in Hestia Control Panel,
+please let our development team know via email at [email protected]. 
+
+We ask that you please include a detailed description of the vulnerability,
+a list of services involved (e.g. exim, dovecot) and the versions which you've tested,
+full steps to reproduce the vulnerability, and include your findings and expected results.

+ 5 - 0
bin/v-acknowledge-user-notification

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: update user notification
 # options: USER NOTIFICATION
+# labels: panel
+#
+# example: v-acknowledge-user-notification
 #
 # The function updates user notification.
 
@@ -14,7 +17,9 @@ user=$1
 id=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 

+ 51 - 7
bin/v-add-backup-host

@@ -1,9 +1,12 @@
 #!/bin/bash
 # info: add backup host
 # options: TYPE HOST USERNAME PASSWORD [PATH] [PORT]
+# labels: 
 #
-# This function adds a backup host
-
+# example: v-add-backup-host sftp backup.acme.com admin p4$$w@Rd
+#          v-add-backup-host b2 bucketName keyID applicationKey
+#
+# Add a new remote backup location. Currently SFTP, FTP and Backblaze are supported 
 
 #----------------------------------------------------------#
 #                    Variable&Function                     #
@@ -19,9 +22,15 @@ path=${5-/backup}
 port=$6
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
+# Paths
+b2cli="/usr/local/bin/b2"
+b2lnk="https://f000.backblazeb2.com/file/backblazefiles/b2/cli/linux/b2"
+
 # Defining ftp command function
 ftpc() {
     ftp -p -n $host $port <<EOF
@@ -41,7 +50,7 @@ sftpc() {
         set count 0
         spawn /usr/bin/sftp -o StrictHostKeyChecking=no -o Port=$port $user@$host
         expect {
-            "password:" {
+            -nocase "password:" {
                 send "$password\r"
                 exp_continue
             }
@@ -100,9 +109,11 @@ if [ "$type" != 'local' ];then
         which expect >/dev/null 2>&1
         check_result $? "expect command not found"  $E_NOTEXIST
     fi
-    if ! (is_ip_format_valid "$host" >/dev/null); then
-        host "$host" >/dev/null 2>&1
-        check_result $? "host connection failed" "$E_CONNECT"
+    if [ "$type" != 'b2' ]; then
+        if ! (is_ip_format_valid "$host" >/dev/null); then
+            host "$host" >/dev/null 2>&1
+            check_result $? "host connection failed" "$E_CONNECT"
+        fi
     fi
 fi
 
@@ -143,6 +154,7 @@ if [ "$type" = 'ftp' ]; then
         exit $E_FTP
     fi
 fi
+
 if [ "$type" = 'sftp' ]; then
     if [ -z $port ]; then
         port=22
@@ -170,14 +182,46 @@ if [ "$type" = 'sftp' ]; then
     fi
 fi
 
+if [ "$type" = 'b2' ]; then
+    # Download b2 binary
+    if [ ! -f "$b2cli" ]; then
+        wget -O $b2cli $b2lnk > /dev/null 2>&1
+        chmod +x $b2cli > /dev/null 2>&1
+        if [ ! -f "$b2cli" ]; then
+            echo "Error: Binary download failed, b2 doesnt work as expected."
+            exit 3
+        fi
+    fi
+
+    # Validate b2 binary
+    b2version="$(b2 version)"
+    if [[ ! "$b2version" =~ "b2 command line tool" ]]; then
+        echo "Error: Binary download failed, b2 doesnt work as expected."
+        exit 3
+    fi
+    
+    b2 clear-account > /dev/null 2>&1
+    b2 authorize-account "$user" "$raw_password"> /dev/null 2>&1
+    b2 ls --long $host $user > /dev/null 2>&1
+    
+    if [ $? -ne 0 ]; then
+        check_result "$E_CONNECT" "b2 failed to verify connection"
+    fi
+fi
 
 # Adding backup host
-if [ $type != 'local' ]; then
+if [ $type != 'local' ] && [ $type != 'b2' ]; then
     new_timestamp
     str="HOST='$host'\nUSERNAME='$user'\nPASSWORD='$password'"
     str="$str\nBPATH='$path'\nPORT='$port'\nTIME='$time'\nDATE='$date'"
     echo -e "$str" > $HESTIA/conf/$type.backup.conf
     chmod 660 $HESTIA/conf/$type.backup.conf
+elif [ $type == 'b2' ]; then
+    new_timestamp
+    str="BUCKET='$host'\nB2_KEYID='$user'\nB2_KEY='$password'"
+    str="$str\nTIME='$time'\nDATE='$date'"
+    echo -e "$str" > $HESTIA/conf/$type.backup.conf
+    chmod 660 $HESTIA/conf/$type.backup.conf
 fi
 
 

+ 4 - 1
bin/v-add-cron-hestia-autoupdate

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: add cron job for hestia autoupdates
 # options: MODE
+# labels: 
 #
 # The function adds cronjob for hestia autoupdate from apt or git.
 
@@ -14,7 +15,9 @@ user=admin
 mode=$1
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -91,7 +94,7 @@ $BIN/v-restart-cron
 check_result $? "Cron restart failed" >/dev/null
 
 # Logging
-log_history "enabled automatic updates"
+$BIN/v-log-action "system" "Info" "Updates" "Automatic updates enabled."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 3
bin/v-add-cron-job

@@ -1,9 +1,12 @@
 #!/bin/bash
 # info: add cron job
 # options: USER MIN HOUR DAY MONTH WDAY COMMAND [JOB] [RESTART]
+# labels: 
+#
+# example: v-add-cron-job admin * * * * * sudo /usr/local/hestia/bin/v-backup-users
 #
 # The function adds a job to cron daemon. When executing commands, any output
-# is  mailed to user's email if parameter REPORTS is set to 'yes'.
+# is mailed to user's email if parameter REPORTS is set to 'yes'.
 
 
 #----------------------------------------------------------#
@@ -22,7 +25,9 @@ job=$8
 restart=$9
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 HIDE=7
@@ -79,11 +84,11 @@ sync_cron_jobs
 increase_user_value $user '$U_CRON_JOBS'
 
 # Restarting crond
-$BIN/v-restart-cron
+$BIN/v-restart-cron $restart
 check_result $? "Cron restart failed" >/dev/null
 
 # Logging
-log_history "added cron job $job"
+$BIN/v-log-action "$user" "Info" "Cron Jobs" "Cron job added (ID: $job, Command: $command)"
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 5 - 0
bin/v-add-cron-letsencrypt-job

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: add letsencrypt cronjob
 # options: NONE
+# labels: 
 #
 # The script for enabling letsencrypt cronjob
 
@@ -10,7 +11,9 @@
 #----------------------------------------------------------#
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -20,6 +23,8 @@ source $HESTIA/conf/hestia.conf
 
 is_system_enabled "$CRON_SYSTEM" 'CRON_SYSTEM'
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 9 - 2
bin/v-add-cron-reports

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add cron reports
-# options: user
+# options: USER
+# labels: 
+#
+# example: v-add-cron-reports admin
 #
 # The script for enabling reports on cron tasks and administrative
 # notifications.
@@ -14,7 +17,9 @@
 user=$1
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -28,6 +33,8 @@ is_system_enabled "$CRON_SYSTEM" 'CRON_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #
@@ -49,7 +56,7 @@ $BIN/v-restart-cron
 check_result $? "Cron restart failed" >/dev/null
 
 # Logging
-log_history "enabled cron reporting"
+$BIN/v-log-action "$user" "Info" "Cron Jobs" "Cron job notifications and reporting enabled."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 5 - 0
bin/v-add-cron-restart-job

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: add cron reports
 # options: NONE
+# labels: 
 #
 # The script for enabling restart cron tasks
 
@@ -10,7 +11,9 @@
 #----------------------------------------------------------#
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -20,6 +23,8 @@ source $HESTIA/conf/hestia.conf
 
 is_system_enabled "$CRON_SYSTEM" 'CRON_SYSTEM'
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 8 - 2
bin/v-add-database

@@ -1,8 +1,11 @@
 #!/bin/bash
 # info: add database
 # options: USER DATABASE DBUSER DBPASS [TYPE] [HOST] [CHARSET]
+# labels: 
 #
-# The function creates the database concatenating username  and user_db.
+# example: v-add-database admin wordpress_db matt qwerty123
+#
+# The function creates the database concatenating username and user_db.
 # Supported types of databases you can get using v-list-sys-config script.
 # If the host isn't stated and there are few hosts configured on the server,
 # then the host will be defined by one of three algorithms. "First" will choose
@@ -26,8 +29,11 @@ charset=${7-UTF8}
 charset=$(echo "$charset" |tr '[:lower:]' '[:upper:]')
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
 source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 if [ "$type" = "pgsql" ]; then
@@ -90,7 +96,7 @@ increase_dbhost_values
 increase_user_value "$user" '$U_DATABASES'
 
 # Logging
-log_history "added $type database $database"
+$BIN/v-log-action "$user" "Info" "Databases" "Added new database $database ($type)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 19 - 9
bin/v-add-database-host

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add new database server
-# options: TYPE HOST DBUSER DBPASS [MAX_DB] [CHARSETS] [TEMPLATE]
+# options: TYPE HOST DBUSER DBPASS [MAX_DB] [CHARSETS] [TEMPLATE] [PORT]
+# labels: 
+#
+# example: v-add-database-host mysql localhost alice p@$$wOrd
 #
 # The function add new database server to the server pool. It supports local
 # and remote database servers, which is useful for clusters. By adding a host
@@ -24,22 +27,26 @@ template=${7}
 port=${8}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
 source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 is_mysql_host_alive() {
     mycnf=$(mktemp)
     echo "[client]">$mycnf
-    echo "host='$HOST'" >> $mycnf
-    echo "user='$USER'" >> $mycnf
-    echo "password='$PASSWORD'" >> $mycnf
-    echo "port='$PORT'" >> $mycnf
+    echo "host='$host'" >> $mycnf
+    echo "user='$user'" >> $mycnf
+    echo "password='$password'" >> $mycnf
+    echo "port='$port'" >> $mycnf
     
     chmod 600 $mycnf
     mysql --defaults-file=$mycnf -e 'SELECT VERSION()' >/dev/null 2>&1
     rm $mycnf
-    if [ '0' -ne "$?" ]; then
+    
+    if [ "$?" -ne '0' ]; then
         echo "Error: MySQL connection to $host failed"
         log_event "$E_CONNECT" "$ARGUMENTS"
         exit $E_CONNECT
@@ -49,7 +56,7 @@ is_mysql_host_alive() {
 is_pgsql_host_alive() {
     export PGPASSWORD="$dbpass"
     psql -h $host -U $dbuser -p $port -c "SELECT VERSION()" > /dev/null 2>&1
-    if [ '0' -ne "$?" ]; then
+    if [ "$?" -ne '0' ]; then
         echo "Error: PostgreSQL connection to $host failed"
         log_event "$E_CONNECT" "$ARGUMENTS"
         exit $E_CONNECT
@@ -70,8 +77,8 @@ if [ -z $template ]; then template="template1"; fi
 database_set_default_ports
 
 is_format_valid 'host' 'dbuser' 'max_db' 'charsets' 'template' 'port'
-#is_system_enabled "$DB_SYSTEM" 'DB_SYSTEM'
-#is_type_valid "$DB_SYSTEM" "$type"
+is_system_enabled "$DB_SYSTEM" 'DB_SYSTEM'
+is_type_valid "$DB_SYSTEM" "$type"
 is_dbhost_new
 is_password_valid
 dbpass="$password"
@@ -81,6 +88,8 @@ case $type in
     pgsql) is_pgsql_host_alive ;;
 esac
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #
@@ -124,6 +133,7 @@ else
 fi
 
 # Logging
+$BIN/v-log-action "system" "Info" "Database" "Added external $type database server ($host) to the system."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 85 - 0
bin/v-add-database-temp-user

@@ -0,0 +1,85 @@
+#!/bin/bash
+# info: add temp database user
+# options: USER DATABASE [TYPE] [HOST] [TTL]
+# labels: hestia database
+#
+# example: v-add-database-temp-user wordress wordpress_db mysql
+#
+# The function creates an temporary database user mysql_sso_db_XXXXXXXX and a random password 
+# The user has an limited validity and only granted access to the specific database 
+# Returns json to be read SSO Script
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+database="$2"
+type=${3-mysql}
+host=$4
+ttl=$5
+
+if [ "$ttl" == '' ]; then
+    ttl=60
+fi
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
+source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DATABASE [TYPE] [HOST]'
+is_format_valid 'user' 'database'
+is_system_enabled "$DB_SYSTEM" 'DB_SYSTEM'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'db' 'DB' "$database"
+is_object_unsuspended 'db' 'DB' "$database"
+get_next_dbhost
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Get database values
+get_database_values
+
+#generate password and unique user 
+dbpass=$(generate_password);
+dbuser="hestia_sso_$(generate_password)";
+
+add_mysql_database_temp_user
+if [ $? -ne 0 ]; then
+    echo "Error: Unable to create temp user"
+    exit 2
+fi;
+
+if [[ "$ttl" -gt 0 ]]; then
+    echo "$BIN/v-delete-database-temp-user $user $database $dbuser mysql $host" | at "now +${ttl} minute" > /dev/null 2>&1
+fi
+echo '{
+    "login": {
+        "user": "'$dbuser'",
+        "password": "'$dbpass'"
+    }
+}'
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Logging
+$BIN/v-log-action "$user" "Info" "Databases" "Granted user $dbuser access to database $database."
+log_event "$OK" "$ARGUMENTS"
+exit

+ 25 - 3
bin/v-add-dns-domain

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add dns domain
-# options: USER DOMAIN IP [NS1] [NS2] [NS3] [..] [NS8] [RESTART]
+# options: USER DOMAIN IP [NS1] [NS2] [NS3] [NS4] [NS5] [NS6] [NS7] [NS8] [RESTART]
+# labels: dns
+#
+# example: v-add-dns-domain admin example.com ns1.example.com ns2.example.com '' '' '' '' '' '' yes
 #
 # The function adds DNS zone with records defined in the template. If the exp
 # argument isn't stated, the expiration date value will be set to next year.
@@ -28,13 +31,17 @@ ns8=${11}
 restart=${12}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
 format_domain
 format_domain_idn
+domain_utf=$(idn -t --quiet -u "$domain_idn")
 
 #----------------------------------------------------------#
 #                    Verifications                         #
@@ -45,11 +52,26 @@ is_format_valid 'user' 'domain' 'ip'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
-is_domain_new 'dns' "$domain"
+
+if [ "$($BIN/v-list-dns-domain $user $domain_utf plain |cut -f 1) " != "$domain" ]; then
+    is_domain_new 'dns' "$domain_utf"
+fi
+if [ "$($BIN/v-list-dns-domain $user $domain_idn plain |cut -f 1) " != "$domain" ]; then
+    is_domain_new 'dns' "$domain_idn"
+else
+    is_domain_new 'dns' "$domain"
+fi
+if [ -z "$(is_ip_format_valid $domain)" ]; then
+    echo "Error: Invalid domain format. IP address detected as input." 
+    exit 1
+fi
+
 is_package_full 'DNS_DOMAINS'
 template=$(get_user_value '$DNS_TEMPLATE')
 is_dns_template_valid $template
 
+is_base_domain_owner "$domain"
+
 if [ ! -z "$ns1" ]; then
     ns1=$(echo $4 |sed -e 's/\.*$//g' -e 's/^\.*//g')
     is_format_valid 'ns1'
@@ -203,7 +225,7 @@ $BIN/v-restart-dns $restart
 check_result $? "DNS restart failed"
 
 # Logging
-log_history "added dns domain $domain"
+$BIN/v-log-action "$user" "Info" "DNS" "Added new DNS domain (Name: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 0
bin/v-add-dns-on-web-alias

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add dns domain or dns record after web domain alias
 # options: USER ALIAS IP [RESTART]
+# labels: dns
+#
+# example: v-add-dns-on-web-alias admin www.example.com 8.8.8.8
 #
 # The function adds dns domain or dns record based on web domain alias.
 
@@ -16,8 +19,11 @@ ip=$3
 restart=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -34,6 +40,8 @@ if [ -e "$USER_DATA/dns/$alias.conf" ]; then
     exit
 fi
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 15 - 1
bin/v-add-dns-record

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add dns record
 # options: USER DOMAIN RECORD TYPE VALUE [PRIORITY] [ID] [RESTART] [TTL]
+# labels: dns
+#
+# example: v-add-dns-record admin acme.com www A 162.227.73.112
 #
 # The call is used for adding new DNS record. Complex records of TXT, MX and
 # SRV types can be used by a filling in the 'value' argument. The function also
@@ -24,14 +27,18 @@ priority=$6
 id=$7
 restart=$8
 ttl=$9
+quiet=${10}
 
 if [ -z "$priority" ]; then
     priority=10
 fi
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Null priority for none MX/SRV records
@@ -47,6 +54,11 @@ if [[ $rtype =~ NS|CNAME|MX|PTR|SRV ]]; then
     fi
 fi
 
+if [[ $rtype =~ NS|CNAME|MX|PTR|SRV ]]; then
+    dvalue=$(idn -t --quiet -a "$dvalue" )
+    record=$(idn -t --quiet -a "$record" )
+fi
+
 # Cleanup quotes on dvalue
 # - [CAA] records will be left unchanged
 # - [SRV] will be  stripped of double quotes even when  containg spaces
@@ -141,7 +153,9 @@ $BIN/v-restart-dns $restart
 check_result $? $E_RESTART 'dns failed to restart'
 
 # Logging
-log_history "added $rtype dns record $record for $domain"
+if [ "$quiet" != "yes" ]; then
+    $BIN/v-log-action "$user" "Info" "DNS" "Added DNS record (Type: $rtype, Value: $record, Domain: $domain)."
+fi
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 6 - 0
bin/v-add-domain

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add web/dns/mail domain
 # options: USER DOMAIN [IP] [RESTART]
+# labels: 
+#
+# example: v-add-domain admin example.com
 #
 # The function adds web/dns/mail domain to a server.
 
@@ -16,8 +19,11 @@ ip=$3
 restart="${4-yes}"
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 

+ 133 - 0
bin/v-add-fastcgi-cache

@@ -0,0 +1,133 @@
+#!/bin/bash
+# info: Enable FastCGI cache for nginx
+# options: USER DOMAIN [DURATION] [DEBUG] [RESTART]
+# labels: hestia web
+#
+# example: v-add-fastcgi-cache user domain.tld 30m
+#
+# The function enables FastCGI cache for nginx
+# Acceptable values for duration is time in seconds (10s) minutes (10m) or days (10d)
+# Add "yes" as last parameter to append debug information to response headers
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+duration=${3-2m}
+debug=${4-no}
+restart=${5-no}
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DOMAIN DEBUG'
+is_format_valid 'user' 'domain'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'web' 'DOMAIN' "$domain"
+is_object_unsuspended 'web' 'DOMAIN' "$domain"
+
+if ! [[ "$duration" =~ ^[0-9].*[s|m|d]$ ]]; then
+   echo "Invalid duration";
+   exit 2;
+fi
+
+if [[ "$duration" =~ ^[0].*[s|m|d]$ ]]; then
+   echo "Invalid duration";
+   exit 2;
+fi
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Load domain data
+parse_object_kv_list $(grep "DOMAIN='$domain'" $USER_DATA/web.conf)
+
+# Check that nginx is not in proxy mode
+if [ "$WEB_SYSTEM" != 'nginx' ]; then
+    echo "Error: nginx is in proxy mode"
+    exit $E_NOTEXIST
+fi
+
+if ! grep --quiet "forcessl" $HESTIA/data/templates/web/nginx/default.tpl; then
+    $BIN/v-update-web-templates
+fi
+
+fastcgi="$HOMEDIR/$user/conf/web/$domain/$WEB_SYSTEM.fastcgi_cache.conf"
+no_cache='$no_cache'
+cookie_session='$cookie_session'
+http_x_update='$http_x_update'
+status='$upstream_cache_status'
+
+cat << EOF > $fastcgi
+    fastcgi_cache $domain;
+    fastcgi_cache_valid 200 $duration;
+    fastcgi_cache_valid 301 302 10m;
+    fastcgi_cache_valid 404 10m;
+    fastcgi_cache_bypass $no_cache;
+    fastcgi_no_cache $no_cache;
+    set $no_cache 0;
+EOF
+
+if [ ! -z "$debug" ]; then
+    echo "    add_header \"X-STATUS\" \"$status\";" >> $fastcgi
+fi
+
+chown root:$user $fastcgi
+chmod 640 $fastcgi
+
+str="fastcgi_cache_path /var/cache/nginx/micro/$domain levels=1:2" 
+str="$str keys_zone=$domain:10m max_size=512m inactive=30m;" 
+conf='/etc/nginx/conf.d/fastcgi_cache_pool.conf'
+if [ -f "$conf" ]; then
+    if [ -z "$(grep "=${domain}:" $conf)" ]; then
+        echo "$str" >> $conf
+    fi
+else
+    echo "$str" >> $conf
+fi
+
+mkdir -p /var/cache/nginx/micro/$domain
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+if [ -z "$FASTCGI_CACHE" ]; then
+    add_object_key "web" 'DOMAIN' "$domain" 'FASTCGI_CACHE' 'ALIAS'
+fi
+if [ -z "$FASTCGI_DURATION" ]; then
+    add_object_key "web" 'DOMAIN' "$domain" 'FASTCGI_DURATION' 'ALIAS'
+fi
+
+# Set FastCGI cache flag to enabled
+update_object_value 'web' 'DOMAIN' "$domain" '$FASTCGI_CACHE' 'yes'
+update_object_value 'web' 'DOMAIN' "$domain" '$FASTCGI_DURATION' "$duration"
+
+if [ "$restart" = "yes" ]; then
+    # Restart web server
+    $BIN/v-restart-web
+    check_result $? "Web server restart failed" > /dev/null
+fi
+
+# Logging
+$BIN/v-log-action "$user" "Info" "Web" "FastCGI cache enabled (Domain: $domain)."
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 11 - 0
bin/v-add-firewall-ban

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add firewall blocking rule
 # options: IP CHAIN
+# labels: 
+#
+# example: v-add-firewall-ban 37.120.129.20 MAIL
 #
 # The function adds new blocking rule to system firewall
 
@@ -20,7 +23,11 @@ chain=$(echo $2|tr '[:lower:]' '[:upper:]')
 iptables="/sbin/iptables"
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/firewall.sh
+source $HESTIA/func/firewall.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -40,6 +47,9 @@ check_hestia_demo_mode
 #                       Action                             #
 #----------------------------------------------------------#
 
+# Self heal iptables links
+heal_iptables_links
+
 # Checking server ip
 if [ -e "$HESTIA/data/ips/$ip" ] || [ "$ip" = '127.0.0.1' ]; then
     exit
@@ -81,6 +91,7 @@ chmod 660 $conf
 #----------------------------------------------------------#
 
 # Logging
+$BIN/v-log-action "system" "Warning" "Firewall" "Banned IP address $ip."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 11 - 0
bin/v-add-firewall-chain

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add firewall chain
 # options: CHAIN [PORT] [PROTOCOL] [PROTOCOL]
+# labels: 
+#
+# example: v-add-firewall-chain CRM 5678 TCP
 #
 # The function adds new rule to system firewall
 
@@ -28,7 +31,11 @@ if [ -z "$hestiaport" ]; then
 fi
 
 # Includes
+# shellcheck /usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck /usr/local/hestia/func/firewall.sh
+source $HESTIA/func/firewall.sh
+# shellcheck /usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -47,6 +54,9 @@ check_hestia_demo_mode
 #                       Action                             #
 #----------------------------------------------------------#
 
+# Self heal iptables links
+heal_iptables_links
+
 # Checking known chains
 case $chain in
     SSH)        # Get ssh port by reading ssh config file.
@@ -96,6 +106,7 @@ chmod 660 $chains
 #----------------------------------------------------------#
 
 # Logging
+$BIN/v-log-action "system" "Info" "Firewall" "Added service to firewall (Service: $chain, Port: $port, Protocol: $protocol)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 6 - 0
bin/v-add-firewall-ipset

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add firewall ipset
 # options: NAME [SOURCE] [IPVERSION] [AUTOUPDATE] [FORCE]
+# labels: hestia
+#
+# example: v-add-firewall-ipset country-nl 'http://ipverse.net/ipblocks/data/countries/nl.zone'
 #
 # The function adds new ipset to system firewall
 
@@ -15,7 +18,9 @@ autoupdate=${4:-yes}
 force=${5:-no}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -183,6 +188,7 @@ fi
 #----------------------------------------------------------#
 
 # Logging
+$BIN/v-log-action "system" "Info" "Firewall" "Added new IP list (Name: $ip_name, IP version: $ip_version, Autoupdate: $autoupdate)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 11 - 0
bin/v-add-firewall-rule

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add firewall rule
 # options: ACTION IP PORT [PROTOCOL] [COMMENT] [RULE]
+# labels: 
+#
+# example: v-add-firewall-rule DROP 185.137.111.77 25
 #
 # The function adds new rule to system firewall
 
@@ -22,7 +25,9 @@ comment=$5
 rule=$6
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Get next firewall rule id
@@ -97,7 +102,13 @@ $BIN/v-update-firewall
 #                       Hestia                             #
 #----------------------------------------------------------#
 
+# Fix missing port value in log if zero
 # Logging
+if [ -z "$port" ]; then
+    port="0"
+fi
+
+$BIN/v-log-action "system" "Info" "Firewall" "Added firewall rule (Action: $action, Port: $port, Protocol: $protocol)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 1
bin/v-add-fs-archive

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: archive directory
-# options: USER ARCHIVE SOURCE
+# options: USER ARCHIVE SOURCE [SOURCE...]
+# labels: 
+#
+# example: v-add-fs-archive admin archive.tar readme.txt
 #
 # The function creates tar archive
 
@@ -8,6 +11,7 @@ user=$1
 archive=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
 
 #----------------------------------------------------------#
@@ -18,6 +22,9 @@ check_args '3' "$#" 'USER ARCHIVE FILE [FILE_2] [FILE_3] [FILE ...]'
 is_format_valid 'user'
 is_object_valid 'user' 'USER' "$user"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
 # Checking user homedir
 homedir=$(grep "^$user:" /etc/passwd |cut -f 6 -d :)
 if [ -z $homedir ]; then

+ 7 - 0
bin/v-add-fs-directory

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add directory
 # options: USER DIRECTORY
+# labels: 
+#
+# example: v-add-fs-directory admin mybar
 #
 # The function creates new directory on the file system
 
@@ -8,6 +11,7 @@ user=$1
 dst_dir=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
 
 #----------------------------------------------------------#
@@ -18,6 +22,9 @@ check_args '2' "$#" 'USER DIR'
 is_format_valid 'user'
 is_object_valid 'user' 'USER' "$user"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
 # Checking user homedir
 homedir=$(grep "^$user:" /etc/passwd | cut -f 6 -d :)
 if [ -z $homedir ]; then

+ 7 - 0
bin/v-add-fs-file

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add file
 # options: USER FILE
+# labels: 
+#
+# example: v-add-fs-file admin readme.md
 #
 # The function creates new files on file system
 
@@ -8,6 +11,7 @@ user=$1
 dst_file=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
 
 #----------------------------------------------------------#
@@ -18,6 +22,9 @@ check_args '2' "$#" 'USER FILE'
 is_format_valid 'user'
 is_object_valid 'user' 'USER' "$user"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
 # Checking user homedir
 homedir=$(grep "^$user:" /etc/passwd | cut -f 6 -d :)
 if [ -z $homedir ]; then

+ 104 - 18
bin/v-add-letsencrypt-domain

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: check letsencrypt domain
 # options: USER DOMAIN [ALIASES] [MAIL]
+# labels: web
+#
+# example: v-add-letsencrypt-domain admin wonderland.com www.wonderland.com
 #
 # The function check and validates domain with Let's Encrypt
 
@@ -16,8 +19,11 @@ aliases=$3
 mail=${4// }
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # LE API
@@ -52,7 +58,8 @@ query_le_v2() {
     # Save http response to file passed as "$4" arg or print to stdout if not provided
     # http response headers are always sent to stdout
     local save_to_file=${4:-"/dev/stdout"}
-    curl --silent --dump-header /dev/stdout --data "$post_data" "$1" --header "$content" --output "$save_to_file"
+    curl --location --insecure --retry 5 --retry-connrefused --silent --dump-header /dev/stdout --data "$post_data" "$1" --header "$content" --output "$save_to_file"
+    debug_log "API call" "exit status: $?"
 }
 
 
@@ -97,6 +104,15 @@ fi
 
 
 
+# Dump debug info
+debug_log() {
+    echo -e "\n==[${1}]==\n${2}\n" >> "$log_file"
+}
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
@@ -105,16 +121,30 @@ fi
 if [ ! -z "$mail" ]; then
     root_domain=$domain
     domain="mail.$root_domain"
-    aliases="$WEBMAIL_ALIAS.$root_domain"
+    webmail=$(get_object_value "mail" "DOMAIN" "$root_domain" '$WEBMAIL');
+    if [ ! -z "$webmail" ]; then
+        aliases="$WEBMAIL_ALIAS.$root_domain"
+    fi
 fi
 
+log_file="/var/log/hestia/LE-${user}-${domain}-$(date +%Y%m%d-%H%M%S).log"
+touch "$log_file"
+chmod 600 "$log_file"
+
+echo -e "\n\n=============================
+WEB_SYSTEM: ${WEB_SYSTEM}
+PROXY_SYSTEM: ${PROXY_SYSTEM}
+user: ${user}
+domain: ${domain}
+" >> "$log_file"
+
 # Registering LetsEncrypt user account
 $BIN/v-add-letsencrypt-user $user
 if [ "$?" -ne 0  ]; then
     touch $HESTIA/data/queue/letsencrypt.pipe
     sed -i "/ $domain /d" $HESTIA/data/queue/letsencrypt.pipe
-    send_notice "LETSENCRYPT" "Account registration failed"
-    check_result $E_CONNECT "LE account registration" > /dev/null
+    send_notice "LETSENCRYPT" "Account registration failed ($user)"
+    check_result $E_CONNECT "LE account registration ($user)" > /dev/null
 fi
 
 # Parsing LetsEncrypt account data
@@ -131,6 +161,12 @@ else
     proto="http-01"
 fi
 
+echo -e "
+- aliases: ${aliases}
+- proto: ${proto}
+- wildcard: ${wildcard}
+" >> "$log_file"
+
 # Check if dns records exist for requested domain/aliases
 if [ "$proto" = "http-01" ]; then
     for identifier in $(echo $domain,$aliases |tr ',' '\n' |sort -u); do
@@ -161,6 +197,9 @@ fi
 answer=$(curl -s -I "$LE_API/directory")
 nonce=$(echo "$answer" |grep -i nonce |cut -f2 -d \ |tr -d '\r\n')
 status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
+
+debug_log "Step 1" "- status: ${status}\n- nonce: ${nonce}\n- answer: ${answer}"
+
 if [[ "$status" -ne 200 ]]; then
     # Delete DNS CAA record
     if [ ! -z "$DNS_SYSTEM" ]; then
@@ -170,7 +209,7 @@ if [[ "$status" -ne 200 ]]; then
             fi
         fi
     fi
-    check_result $E_CONNECT "Let's Encrypt nonce request status $status"
+    check_result $E_CONNECT "Let's Encrypt nonce request status $status ($domain)"
 fi
 
 # Placing new order / STEP 2
@@ -189,6 +228,9 @@ nonce=$(echo "$answer" |grep -i nonce |cut -f2 -d \ |tr -d '\r\n')
 authz=$(echo "$answer" |grep "acme/authz" |cut -f2 -d '"')
 finalize=$(echo "$answer" |grep 'finalize":' |cut -f4 -d '"')
 status=$(echo "$answer" |grep HTTP/ |tail -n1 |cut -f2 -d ' ')
+
+debug_log "Step 2" "- status: ${status}\n- nonce: ${nonce}\n- authz: ${authz}\n- finalize: ${finalize}\n- payload: ${payload}\n- answer: ${answer}"
+
 if [[ "$status" -ne 201 ]]; then
     # Delete DNS CAA record
     if [ ! -z "$DNS_SYSTEM" ]; then
@@ -198,17 +240,20 @@ if [[ "$status" -ne 201 ]]; then
             fi
         fi
     fi
-    check_result $E_CONNECT "Let's Encrypt new auth status $status"
+    check_result $E_CONNECT "Let's Encrypt new auth status $status ($domain)"
 fi
 
 # Requesting authorization token / STEP 3
 for auth in $authz; do
     payload=''
     answer=$(query_le_v2 "$auth" "$payload" "$nonce")
-    url=$(echo "$answer" |grep -A3 $proto |grep url |cut -f 4 -d \")
+    url=$(echo "$answer" |grep -A3 $proto |grep -m1 url |cut -f 4 -d \")
     token=$(echo "$answer" |grep -A3 $proto |grep token |cut -f 4 -d \")
     nonce=$(echo "$answer" |grep -i nonce |cut -f2 -d \ |tr -d '\r\n')
     status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
+
+    debug_log "Step 3" "- status: ${status}\n- nonce: ${nonce}\n- url: ${url}\n- token: ${token}\n- answer: ${answer}"
+
     if [[ "$status" -ne 200 ]]; then
         # Delete DNS CAA record
         if [ ! -z "$DNS_SYSTEM" ]; then
@@ -221,7 +266,7 @@ for auth in $authz; do
                 fi
             fi
         fi
-        check_result $E_CONNECT "Let's Encrypt acme/authz bad status $status"
+        check_result $E_CONNECT "Let's Encrypt acme/authz bad status $status ($domain)"
     fi
 
     # Accepting challenge / STEP 4
@@ -234,13 +279,13 @@ for auth in $authz; do
             $BIN/v-delete-dns-record $user $domain $old_record
         done
         $BIN/v-add-dns-record $user $domain "_acme-challenge" "TXT" $record
-        check_result $? "DNS _acme-challenge record wasn't created"
+        check_result $? "DNS _acme-challenge record wasn't created ($domain)"
     else
         if [ -z "$mail" ]; then
             if [ "$WEB_SYSTEM" = 'nginx' ] || [ "$PROXY_SYSTEM" = 'nginx' ]; then
                 conf="$HOMEDIR/$user/conf/web/$domain/nginx.conf_letsencrypt"
                 sconf="$HOMEDIR/$user/conf/web/$domain/nginx.ssl.conf_letsencrypt"
-                echo 'location ~ "^/\.well-known/acme-challenge/(.*)$" {' \
+                echo 'location ~ "^/\.well-known/acme-challenge/([-_A-Za-z0-9]+)$" {' \
                     > $conf
                 echo '    default_type text/plain;' >> $conf
                 echo '    return 200 "$1.'$THUMB'";' >> $conf
@@ -300,6 +345,9 @@ for auth in $authz; do
         nonce=$(echo "$answer" |grep -i nonce |cut -f2 -d \ |tr -d '\r\n')
         status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
         details=$(echo "$answer"| grep detail | cut -f 1 -d ',' | cut -f 2-4 -d ':' | cut -f 2 -d '"')
+
+        debug_log "Step 5" "- status: ${status}\n- nonce: ${nonce}\n- validation: ${validation}\n- details: ${details}\n- answer: ${answer}"
+
         if [[ "$status" -ne 200 ]]; then
             # Delete DNS CAA record
             if [ ! -z "$DNS_SYSTEM" ]; then
@@ -312,7 +360,8 @@ for auth in $authz; do
                     fi
                 fi
             fi
-            check_result $E_CONNECT "Let's Encrypt validation status $status. Details: $details"
+            debug_log "Abort Step 5" "=> Wrong status"
+            check_result $E_CONNECT "Let's Encrypt validation status $status ($domain). Details: $details"
         fi
 
         i=$((i + 1))
@@ -328,7 +377,8 @@ for auth in $authz; do
                     fi
                 fi
             fi
-            check_result $E_CONNECT "Let's Encrypt domain validation timeout"
+            debug_log "Abort Step 5" "=> Too many validation retries"
+            check_result $E_CONNECT "Let's Encrypt domain validation timeout ($domain)"
         fi
         sleep $((i*2))
     done
@@ -344,7 +394,7 @@ for auth in $authz; do
                 fi
             fi
         fi
-        check_result $E_CONNECT "Let's Encrypt domain verification failed"
+        check_result $E_CONNECT "Let's Encrypt domain verification failed ($domain)"
     fi
 done
 
@@ -359,17 +409,47 @@ answer=$(query_le_v2 "$finalize" "$payload" "$nonce")
 nonce=$(echo "$answer" |grep -i nonce |cut -f2 -d \ |tr -d '\r\n')
 status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
 certificate=$(echo "$answer"|grep 'certificate":' |cut -f4 -d '"')
+
+debug_log "Step 6" "- status: ${status}\n- nonce: ${nonce}\n- payload: ${payload}\n- certificate: ${certificate}\n- answer: ${answer}"
+
 if [[ "$status" -ne 200 ]]; then
     [ -d "$ssl_dir" ] && rm -rf "$ssl_dir"
-    check_result $E_CONNECT "Let's Encrypt finalize bad status $status"
+    check_result $E_CONNECT "Let's Encrypt finalize bad status $status ($domain)"
 fi
 
 # Downloading signed certificate / STEP 7
-answer=$(query_le_v2 "$certificate" "" "$nonce" "$ssl_dir/$domain.pem")
-status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
+status=0
+retry=0
+
+while [[ $status != 200 && $retry -lt 3 ]]; do
+
+    answer=$(query_le_v2 "$certificate" "" "$nonce" "$ssl_dir/$domain.pem")
+    status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
+
+    debug_log "Step 7" "- status: ${status}\n- retry: ${retry}\n- answer: ${answer}"
+
+    if [[ $status != 200 ]]; then
+        retry=$((retry + 1))
+        sleep $((retry * 2))    # Sleep for 2s, 4s, 6s, 8s
+    fi
+
+done
+
+# Fallback on depreciated download method for certs (unauthenticated GET)
+if [[ $status != 200 ]]; then
+    answer=$(curl  --insecure --retry 5 --retry-connrefused --silent --dump-header /dev/stdout "$certificate" --output "$ssl_dir/$domain.pem")
+    status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
+
+    debug_log "Step 7 - Fallback" "- status: ${status}\n- answer: ${answer}"
+fi
+
+debug_log "CERT DIR" "$(ls -las "$ssl_dir/")"
+debug_log "CERT PEM" "$(cat "$ssl_dir/$domain.pem")"
+
+
 if [[ "$status" -ne 200 ]]; then
     [ -d "$ssl_dir" ] && rm -rf "$ssl_dir"
-    check_result $E_NOTEXIST "Let's Encrypt downloading signed cert failed status:$status"
+    check_result $E_NOTEXIST "Let's Encrypt downloading signed cert failed status:$status ($domain)"
 fi
 
 # Splitting up downloaded pem
@@ -381,10 +461,13 @@ ca_end=$(grep -n  "BEGIN" $ssl_dir/$domain.pem |tail -n1 |cut -f 1 -d :)
 ca_end=$(( pem_lines - crt_end + 1 ))
 tail -n $ca_end $ssl_dir/$domain.pem > $ssl_dir/$domain.ca
 
+debug_log "CERT CRT" "$(cat "$ssl_dir/$domain.crt")"
+debug_log "CERT CA-1" "$(cat "$ssl_dir/$domain.ca")"
 # Temporary fix for double "END CERTIFICATE"
 if [[ $(head -n 1 $ssl_dir/$domain.ca) = "-----END CERTIFICATE-----" ]]; then
     sed -i '1,2d' $ssl_dir/$domain.ca
 fi
+debug_log "CERT CA-2" "$(cat "$ssl_dir/$domain.ca")"
 
 # Rename certs for mail
 if [ ! -z "$mail" ]; then
@@ -413,7 +496,7 @@ if [ "$?" -ne '0' ]; then
     [ -d "$ssl_dir" ] && rm -rf "$ssl_dir"
     touch $HESTIA/data/queue/letsencrypt.pipe
     sed -i "/ $domain /d" $HESTIA/data/queue/letsencrypt.pipe
-    send_notice 'LETSENCRYPT' "$domain certificate installation failed"
+    send_notice 'LETSENCRYPT' "$domain certificate installation failed ($domain)"
     check_result $? "SSL install" > /dev/null
 fi
 
@@ -464,4 +547,7 @@ send_notice 'LETSENCRYPT' "$domain SSL has been installed successfully"
 # Logging
 log_event "$OK" "$ARGUMENTS"
 
+# Cleanup debug since the SSL was issues succesfully
+rm -f "$log_file"
+
 exit

+ 16 - 3
bin/v-add-letsencrypt-host

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add letsencrypt for host and backend
-# options:
+# options: NONE
+# labels: hestia
+#
+# example: v-add-letsencrypt-host
 #
 # The function check and validates the backend certificate and generate
 # a new let's encrypt certificate.
@@ -10,17 +13,27 @@
 #                    Variable&Function                     #
 #----------------------------------------------------------#
 
+# make sure path is always loaded 
+source /etc/profile
+
 # Argument definition
-domain=$HOSTNAME
+domain=$(hostname -f);
+if [ -z $domain ]; then 
+    domain=$HOSTNAME;
+fi
 user="$($HESTIA/bin/v-search-domain-owner "$domain" web)"
 [[ -z "$user" ]] && user="admin"
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
-
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#

+ 8 - 2
bin/v-add-letsencrypt-user

@@ -1,8 +1,11 @@
 #!/bin/bash
 # info: register letsencrypt user account
 # options: USER
+# labels: web
 #
-# The function creates and register LetsEncrypt account 
+# example: v-add-letsencrypt-user bob
+#
+# The function creates and register LetsEncrypt account
 
 
 #----------------------------------------------------------#
@@ -13,7 +16,9 @@
 user=$1
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # LE API
@@ -63,7 +68,8 @@ if [ ! -z "$KID" ]; then
     exit
 fi
 
-
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#

+ 8 - 2
bin/v-add-mail-account

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail domain account
 # options: USER DOMAIN ACCOUNT PASSWORD [QUOTA]
+# labels: mail
+#
+# example: v-add-mail-account user example.com john P4$$vvOrD
 #
 # The function add new email account.
 
@@ -17,8 +20,11 @@ password=$4; HIDE=4
 quota=${5-unlimited}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -62,7 +68,7 @@ if [[ "$MAIL_SYSTEM" =~ exim ]]; then
     if [ "$quota" = 'unlimited' ]; then
         quota='0'
     fi
-    str="$account:$md5:$user:mail::$HOMEDIR/$user::userdb_quota_rule=*:storage=${quota}M"
+    str="$account:$md5:$user:mail::$HOMEDIR/$user:${quota}:userdb_quota_rule=*:storage=${quota}M"
     echo $str >> $HOMEDIR/$user/conf/mail/$domain/passwd
 fi
 
@@ -92,7 +98,7 @@ increase_user_value "$user" '$U_MAIL_ACCOUNTS'
 update_object_value 'mail' 'DOMAIN' "$domain" '$ACCOUNTS' "$accounts"
 
 # Logging
-log_history "added mail account $account@$domain"
+$BIN/v-log-action "$user" "Info" "Mail" "Added new mail account ($account@$domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 1
bin/v-add-mail-account-alias

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail account alias aka nickname
 # options: USER DOMAIN ACCOUNT ALIAS
+# labels: mail
+#
+# example: v-add-mail-account-alias admin acme.com alice alicia
 #
 # The function add new email alias.
 
@@ -17,8 +20,11 @@ account=$3
 malias=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -71,7 +77,7 @@ fi
 update_object_value "mail/$domain" 'ACCOUNT' "$account"  '$ALIAS' "$aliases"
 
 # Logging
-log_history "added alias $malias to $account@$domain "
+$BIN/v-log-action "$user" "Info" "Mail" "Added alias $malias to mail account $account@$domain."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 1
bin/v-add-mail-account-autoreply

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail account autoreply message
 # options: USER DOMAIN ACCOUNT MESSAGE
+# labels: mail
+#
+# example: v-add-mail-account-autoreply admin example.com user Hello from e-mail!
 #
 # The function add new email account.
 
@@ -17,8 +20,11 @@ account=$3
 autoreply=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Define mail user
@@ -76,7 +82,7 @@ chmod 660 $USER_DATA/mail/$account@$domain.msg
 update_object_value "mail/$domain" 'ACCOUNT' "$account" '$AUTOREPLY' 'yes'
 
 # Logging
-log_history "added autoreply message on $account@$domain"
+$BIN/v-log-action "$user" "Info" "Mail" "Added auto-reply message for mail account $account@$domain."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 11 - 2
bin/v-add-mail-account-forward

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail account forward address
 # options: USER DOMAIN ACCOUNT FORWARD
+# labels: mail
+#
+# example: v-add-mail-account-forward admin acme.com alice bob
 #
 # The function add new email account.
 
@@ -17,8 +20,11 @@ account=$3
 email_forward=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -31,7 +37,10 @@ format_domain_idn
 #----------------------------------------------------------#
 
 check_args '4' "$#" 'USER DOMAIN ACCOUNT FORWARD'
-is_format_valid 'user' 'domain' 'account' 'email_forward'
+is_format_valid 'user' 'domain' 'account'
+if [ "$email_forward"  != ':blackhole:' ]; then
+    is_format_valid 'email_forward'
+fi
 is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
@@ -76,7 +85,7 @@ fi
 update_object_value "mail/$domain" 'ACCOUNT' "$account"  '$FWD' "$fwd"
 
 # Logging
-log_history "added forwarding from $account@$domain to $email_forward"
+$BIN/v-log-action "$user" "Warning" "Mail" "Mail forwarding on mail account $account@$domain enabled (send to: $email_forward)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 2
bin/v-add-mail-account-fwd-only

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail account forward-only flag
 # options: USER DOMAIN ACCOUNT
+# labels: mail
+#
+# example: v-add-mail-account-fwd-only admin example.com user
 #
 # The function adds fwd-only flag
 
@@ -16,8 +19,11 @@ domain_idn=$2
 account=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Define mail user
@@ -49,7 +55,7 @@ is_object_unsuspended "mail/$domain" 'ACCOUNT' "$account"
 fwd=$(get_object_value "mail/$domain" 'ACCOUNT' "$account" '$FWD')
 if [ -z "$fwd" ]; then
     echo "Error: forward doesn't exist"
-    log_event "$E_NOTEXIST $ARGUMENTS"
+    log_event "$E_NOTEXIST" "$ARGUMENTS"
     exit $E_NOTEXIST
 fi
 
@@ -77,7 +83,7 @@ add_object_key "mail/$domain" 'ACCOUNT' "$account" 'FWD_ONLY' 'MD5'
 update_object_value "mail/$domain" 'ACCOUNT' "$account"  '$FWD_ONLY' "yes"
 
 # Logging
-log_history "added fwd_only flag for $account@$domain"
+$BIN/v-log-action "$user" "Warning" "Mail" "Forward-only flag enabled on mail account $account@$domain."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 30 - 25
bin/v-add-mail-domain

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail domain
 # options: USER DOMAIN [ANTISPAM] [ANTIVIRUS] [DKIM] [DKIM_SIZE]
+# labels: mail
+#
+# example: v-add-mail-domain admin mydomain.tld
 #
 # The function adds MAIL domain.
 
@@ -18,10 +21,14 @@ dkim=${5-yes}
 dkim_size=${6-1024}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
-source $HESTIA/conf/hestia.conf
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
 
 # Define mail user
 if [ "$MAIL_SYSTEM" = 'exim4' ]; then
@@ -33,7 +40,7 @@ fi
 # Additional argument formatting
 format_domain
 format_domain_idn
-
+domain_utf=$(idn -t --quiet -u "$domain_idn")
 
 #----------------------------------------------------------#
 #                    Verifications                         #
@@ -44,10 +51,25 @@ is_format_valid 'user' 'domain' 'antispam' 'antivirus' 'dkim' 'dkim_size'
 is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
-is_domain_new 'mail' "$domain"
+
+if [ "$($BIN/v-list-mail-domain $user $domain_utf plain |cut -f 1) " != "$domain" ]; then
+    is_domain_new 'mail' "$domain_utf"
+fi
+if [ "$($BIN/v-list-mail-domain $user $domain_idn plain |cut -f 1) " != "$domain" ]; then
+    is_domain_new 'mail' "$domain_idn"
+else
+    is_domain_new 'mail' "$domain"
+fi
+if [ -z "$(is_ip_format_valid $domain)" ]; then
+    echo "Error: Invalid domain format. IP address detected as input." 
+    exit 1
+fi
+
 is_package_full 'MAIL_DOMAINS'
 is_dir_symlink $HOMEDIR/$user/mail
 
+is_base_domain_owner "$domain"
+
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
 
@@ -69,7 +91,7 @@ fi
 new_timestamp
 
 # Adding domain to mail.conf
-s="DOMAIN='$domain' ANTIVIRUS='$antivirus' ANTISPAM='$antispam' DKIM='$dkim'"
+s="DOMAIN='$domain' ANTIVIRUS='$antivirus' ANTISPAM='$antispam' DKIM='$dkim' WEBMAIL=''"
 s="$s SSL='no' LETSENCRYPT='no' CATCHALL='' ACCOUNTS='0' U_DISK='0' SUSPENDED='no' TIME='$time'"
 s="$s DATE='$date'"
 echo $s >> $USER_DATA/mail.conf
@@ -101,23 +123,6 @@ if [[ "$MAIL_SYSTEM" =~ exim ]]; then
         echo "$local_ip" > $HOMEDIR/$user/conf/mail/$domain/ip
     fi
 
-    # Touch mailhelo.conf if it doesnt exist
-    if [ ! -f "/etc/exim4/mailhelo.conf" ]; then
-        touch /etc/exim4/mailhelo.conf
-    fi
-
-    # Setting HELO for mail domain
-    if [ ! -z "$local_ip" ]; then
-        IP_RDNS=$(is_ip_rdns_valid "$local_ip")
-        if [ ! -z "$IP_RDNS" ]; then
-            if [ $(grep -s "^${domain}:" /etc/exim4/mailhelo.conf) ]; then
-                sed -i "/^${domain}:/c\\${domain}:${IP_RDNS}" /etc/exim4/mailhelo.conf
-            else
-                echo ${domain}:${IP_RDNS} >> /etc/exim4/mailhelo.conf
-            fi
-        fi        
-    fi
-
     # Adding antispam protection
     if [ "$antispam" = 'yes' ]; then
         touch $HOMEDIR/$user/conf/mail/$domain/antispam
@@ -155,18 +160,18 @@ if [ ! -z "$DNS_SYSTEM" ] && [ "$dkim" = 'yes' ]; then
         p=$(cat $USER_DATA/mail/$domain.pub|grep -v ' KEY---'|tr -d '\n')
         record='_domainkey'
         policy="\"t=y; o=~;\""
-        $BIN/v-add-dns-record $user $domain $record TXT "$policy" '' '' 'no'
+        $BIN/v-add-dns-record $user $domain $record TXT "$policy" '' '' 'no' '' 'yes'
 
         record='mail._domainkey'
         selector="\"v=DKIM1\; k=rsa\; p=$p\""
-        $BIN/v-add-dns-record $user $domain $record TXT "$selector"
+        $BIN/v-add-dns-record $user $domain $record TXT "$selector" '' '' 'yes' '' 'yes'
     fi
 fi
 
 # Add webmail configuration to mail domain
 if [ ! -z "$WEB_SYSTEM" ] || [ ! -z "$PROXY_SYSTEM" ]; then
     if [ ! -z "$IMAP_SYSTEM" ]; then
-        $BIN/v-add-sys-webmail $user $domain ''
+        $BIN/v-add-mail-domain-webmail $user $domain '' 'no'
     fi
 fi
     
@@ -190,7 +195,7 @@ $BIN/v-restart-proxy $restart
 check_result $? "Proxy restart failed" >/dev/null
 
 # Logging
-log_history "added mail domain $domain"
+$BIN/v-log-action "$user" "Info" "Mail" "Added new mail domain ($domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 1
bin/v-add-mail-domain-antispam

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail domain antispam support
 # options: USER DOMAIN
+# labels: mail
+#
+# example: v-add-mail-domain-antispam admin mydomain.tld
 #
 # The function enables spamassasin for incoming emails.
 
@@ -15,8 +18,11 @@ domain=$2
 domain_idn=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -60,7 +66,7 @@ fi
 update_object_value 'mail' 'DOMAIN' "$domain" '$ANTISPAM' 'yes'
 
 # Logging
-log_history "enabled antispam on $domain"
+$BIN/v-log-action "$user" "Info" "Mail" "Anti-spam protection enabled (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 1
bin/v-add-mail-domain-antivirus

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail domain antivirus support
 # options: USER DOMAIN
+# labels: mail
+#
+# example: v-add-mail-domain-antivirus admin mydomain.tld
 #
 # The function enables clamav scan for incoming emails.
 
@@ -15,8 +18,11 @@ domain=$2
 domain_idn=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -60,7 +66,7 @@ fi
 update_object_value 'mail' 'DOMAIN' "$domain" '$ANTIVIRUS' 'yes'
 
 # Logging
-log_history "enabled antivirus on $domain"
+$BIN/v-log-action "$user" "Info" "Mail" "Anti-virus scanning enabled (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 1
bin/v-add-mail-domain-catchall

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail domain catchall account
 # options: USER DOMAIN EMAIL
+# labels: mail
+#
+# example: v-add-mail-domain-catchall admin example.com [email protected]
 #
 # The function enables catchall account for incoming emails.
 
@@ -16,8 +19,11 @@ domain_idn=$2
 email="$3"
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -61,7 +67,7 @@ fi
 update_object_value 'mail' 'DOMAIN' "$domain" '$CATCHALL' "$email"
 
 # Logging
-log_history "added $email as catchall email for $domain"
+$BIN/v-log-action "$user" "Warning" "Mail" "Catch-all forwarding enabled (Domain: $domain, Send to: $email)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 10 - 4
bin/v-add-mail-domain-dkim

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add mail domain dkim support
 # options: USER DOMAIN [DKIM_SIZE]
+# labels: mail
+#
+# example: v-add-mail-domain-dkim admin acme.com
 #
 # The function adds DKIM signature to outgoing domain emails.
 
@@ -16,8 +19,11 @@ domain_idn=$2
 dkim_size=${3-1024}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Define mail user
@@ -71,12 +77,12 @@ fi
 if [ ! -z "$DNS_SYSTEM" ] && [ -e "$USER_DATA/dns/$domain.conf" ]; then
     p=$(cat $USER_DATA/mail/$domain.pub |grep -v ' KEY---' |tr -d '\n')
     record="_domainkey"
-    policy="\"t=y; o=~;\""
-    $BIN/v-add-dns-record $user $domain $record TXT "$policy" '' '' 'no'
+    policy="\"t=y\; o=~\;\""
+    $BIN/v-add-dns-record $user $domain $record TXT "$policy" '' '' 'no' '' 'yes'
 
     record="mail._domainkey"
     selector="\"v=DKIM1\; k=rsa\; p=$p\""
-    $BIN/v-add-dns-record $user $domain $record TXT "$selector"
+    $BIN/v-add-dns-record $user $domain $record TXT "$selector" '' '' 'yes' '' 'yes'
 fi
 
 
@@ -89,7 +95,7 @@ update_object_value 'mail' 'DOMAIN' "$domain" '$DKIM' 'yes'
 increase_user_value "$user" '$U_MAIL_DKIM'
 
 # Logging
-log_history "enabled DKIM support for $domain"
+$BIN/v-log-action "$user" "Info" "Mail" "DKIM message signing enabled (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 77 - 0
bin/v-add-mail-domain-smtp-relay

@@ -0,0 +1,77 @@
+#!/bin/bash
+# info: Add mail domain smtp relay support
+# options: USER DOMAIN HOST USERNAME PASSWORD [PORT]
+# labels: mail
+#
+# example: v-add-mail-domain-smtp-relay user domain.tld srv.smtprelay.tld uname123 pass12345
+#
+# This function adds mail domain smtp relay support.
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+host=$3
+username=$4
+password=$5
+port=${6-587}
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '5' "$#" 'USER DOMAIN HOST USERNAME PASSWORD'
+is_format_valid 'port' 'user' 'domain'
+is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'mail' 'DOMAIN' "$domain"
+is_object_unsuspended 'mail' 'DOMAIN' "$domain"
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+cat >/etc/exim4/domains/${domain}/smtp_relay.conf << EOL
+host:$host
+port:$port
+user:$username
+pass:$password
+EOL
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Adding smtp relay values in config
+if [ -z "$U_SMTP_RELAY" ]; then
+    add_object_key 'mail' 'DOMAIN' "$domain" 'U_SMTP_RELAY' 'ACCOUNTS'
+    add_object_key 'mail' 'DOMAIN' "$domain" 'U_SMTP_RELAY_HOST' 'ACCOUNTS'
+    add_object_key 'mail' 'DOMAIN' "$domain" 'U_SMTP_RELAY_PORT' 'ACCOUNTS'
+    add_object_key 'mail' 'DOMAIN' "$domain" 'U_SMTP_RELAY_USERNAME' 'ACCOUNTS'
+    add_object_key 'mail' 'DOMAIN' "$domain" 'U_SMTP_RELAY_PASSWORD' 'ACCOUNTS'
+fi
+
+update_object_value 'mail' 'DOMAIN' "$domain" '$U_SMTP_RELAY' 'true'
+update_object_value 'mail' 'DOMAIN' "$domain" '$U_SMTP_RELAY_HOST' "$host"
+update_object_value 'mail' 'DOMAIN' "$domain" '$U_SMTP_RELAY_PORT' "$port"
+update_object_value 'mail' 'DOMAIN' "$domain" '$U_SMTP_RELAY_USERNAME' "$username"
+update_object_value 'mail' 'DOMAIN' "$domain" '$U_SMTP_RELAY_PASSWORD' "$password"
+
+# Logging
+$BIN/v-log-action "$user" "Info" "Mail" "SMTP Relay enabled (Domain: $domain, Host: $host, Port: $port)."
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 6 - 1
bin/v-add-mail-domain-ssl

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: add mail SSL for $domain
 # options: USER DOMAIN SSL_DIR [RESTART]
+# labels: hestia
 #
 # The function turns on SSL support for a mail domain. Parameter ssl_dir
 # is a path to a directory where 2 or 3 ssl files can be found. Certificate file 
@@ -31,9 +32,13 @@ fi
 domain_idn=$(idn -t --quiet -a "$domain")
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -107,7 +112,7 @@ $BIN/v-restart-proxy $restart
 check_result $? "Proxy restart failed" >/dev/null
 
 # Logging
-log_history "enabled mail ssl support for $domain"
+$BIN/v-log-action "$user" "Info" "Mail" "SSL enabled (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 65 - 20
bin/v-add-sys-webmail → bin/v-add-mail-domain-webmail

@@ -1,9 +1,13 @@
 #!/bin/bash
 # info: add webmail support for a domain
-# options: USER DOMAIN [RESTART] [QUIET]
+# options: USER DOMAIN [WEBMAIL] [RESTART] [QUIET]
+# labels: hestia
 #
-# this function adds support for webmail services
-# to a mail domain.
+# example: v-add-sys-webmail user domain.com
+# example: v-add-sys-webmail user domain.com rainloop
+# example: v-add-sys-webmail user domain.com roundcube
+#
+# this function enables webmail client for a mail domain.
 
 #----------------------------------------------------------#
 #                    Variable&Function                     #
@@ -12,8 +16,9 @@
 # Argument definition
 user=$1
 domain=$2
-restart="$3"
-quiet=$4
+webmail=$3
+restart="$4"
+quiet=$5
 
 # Additional argument formatting
 if [[ "$domain" =~ [[:upper:]] ]]; then
@@ -26,12 +31,14 @@ if [[ "$domain" =~ .*\.$ ]]; then
     domain=$(echo "$domain" |sed -e "s/\.$//")
 fi
 
-domain_idn=$(idn -t --quiet -a "$domain")
-
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -43,15 +50,25 @@ format_domain_idn
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '2' "$#" 'USER DOMAIN [RESTART]'
+if [ -z "$webmail" ]; then
+    for client in ${WEBMAIL_SYSTEM//,/ };do
+        webmail="$client"
+    done
+fi
+
+check_args '2' "$#" 'USER DOMAIN [WEBMAIL] [RESTART]'
 is_format_valid 'user' 'domain'
 is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
 is_system_enabled "$IMAP_SYSTEM" 'IMAP_SYSTEM'
+is_type_valid "$WEBMAIL_SYSTEM" "$webmail"
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'mail' 'DOMAIN' "$domain"
 is_object_unsuspended 'mail' 'DOMAIN' "$domain"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
@@ -82,23 +99,44 @@ else
 
         if [ "$dns_domain" = "$domain" ]; then
             if [ -z "$webmail_record" ]; then
-                $BIN/v-add-dns-record $user $domain $WEBMAIL_ALIAS A $ip
+                if [ "$quiet" = "yes" ]; then
+                    $BIN/v-add-dns-record $user $domain $WEBMAIL_ALIAS A $ip '' '' $restart '' 'yes'
+                else
+                    $BIN/v-add-dns-record $user $domain $WEBMAIL_ALIAS A $ip '' '' $restart '' 'yes'
+                fi
             else
-                $BIN/v-delete-dns-record $user $domain $webmail_record
-                $BIN/v-add-dns-record $user $domain $WEBMAIL_ALIAS A $ip
+                if [ "$quiet" = "yes" ]; then
+                    $BIN/v-delete-dns-record $user $domain $webmail_record $restart 'yes'
+                    $BIN/v-add-dns-record $user $domain $WEBMAIL_ALIAS A $ip '' '' $restart '' 'yes'
+                else
+                    $BIN/v-delete-dns-record $user $domain $webmail_record $restart 'yes'
+                    $BIN/v-add-dns-record $user $domain $WEBMAIL_ALIAS A $ip '' '' $restart '' 'yes'
+                fi
             fi
         fi
     fi
-
-    # Add webmail configuration to mail domain
-    WEBMAIL_TEMPLATE="default"
-    if [ "$WEB_SYSTEM" = "nginx" ]; then
-        WEBMAIL_TEMPLATE="web_system"
+    
+    if [ "$webmail" == "roundcube" ]; then
+        WEBMAIL_TEMPLATE="default"
+        if [ ! -z "$PROXY_SYSTEM" ]; then
+            PROXY_TEMPLATE="default"
+        fi
+        # Add webmail configuration to mail domain
+        WEBMAIL_TEMPLATE="default"
+        if [ "$WEB_SYSTEM" = "nginx" ]; then
+            WEBMAIL_TEMPLATE="web_system"
+        fi
+    else
+        WEBMAIL_TEMPLATE="rainloop"
+        if [ ! -z "$PROXY_SYSTEM" ]; then
+            PROXY_TEMPLATE="default_rainloop"
+        fi
     fi
+    
     add_webmail_config "$WEB_SYSTEM" "${WEBMAIL_TEMPLATE}.tpl"
 
     if [ ! -z "$PROXY_SYSTEM" ]; then
-        add_webmail_config "$PROXY_SYSTEM" "default.tpl"
+        add_webmail_config "$PROXY_SYSTEM" "${PROXY_TEMPLATE}.tpl"
     fi
 
     # Enable SSL for webmail if available
@@ -106,16 +144,23 @@ else
         add_webmail_config "$WEB_SYSTEM" "${WEBMAIL_TEMPLATE}.stpl"
 
         if [ ! -z "$PROXY_SYSTEM" ]; then
-            add_webmail_config "$PROXY_SYSTEM" "default.stpl"
+            add_webmail_config "$PROXY_SYSTEM" "${PROXY_TEMPLATE}.stpl"
         fi
     fi
 fi
 
+WEBMAIL=$(get_object_value 'web' 'DOMAIN' "$domain" "$WEBMAIL")
+if [ -z "$WEBMAIL" ]; then
+    add_object_key 'mail' 'DOMAIN' "$domain" 'WEBMAIL' 'SSL'
+fi
+
+# Set SSL as enabled in configuration
+update_object_value 'mail' 'DOMAIN' "$domain" '$WEBMAIL' "$webmail"
 #----------------------------------------------------------#
 #                       Hestia                             #
 #----------------------------------------------------------#
 
-if [ "$3" = 'yes' ]; then 
+if [ "$restart" = 'yes' ]; then 
     # Restarting web server
     $BIN/v-restart-web $restart
     check_result $? "Web restart failed" >/dev/null
@@ -126,7 +171,7 @@ fi
 
 # Logging
 if [ "$quiet" != 'yes' ]; then
-    log_history "enabled webmail support for $domain"
+    $BIN/v-log-action "$user" "Info" "Mail" "Webmail access enabled (Domain: $domain)."
 fi
 log_event "$OK" "$ARGUMENTS"
 

+ 8 - 0
bin/v-add-remote-dns-domain

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add remote dns domain
 # options: USER DOMAIN [FLUSH]
+# labels: dns
+#
+# example: v-add-remote-dns-domain admin mydomain.tld yes
 #
 # The function synchronize dns domain with the remote server.
 
@@ -16,8 +19,11 @@ flush=$3
 
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/remote.sh
 source $HESTIA/func/remote.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -31,6 +37,8 @@ is_system_enabled "$DNS_CLUSTER" 'DNS_CLUSTER'
 is_procces_running
 remote_dns_health_check
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 12 - 1
bin/v-add-remote-dns-host

@@ -1,8 +1,15 @@
 #!/bin/bash
 # info: add new remote dns host
 # options: HOST PORT USER PASSWORD [TYPE] [DNS_USER]
+# labels: dns
+#
+# example: v-add-remote-dns-host slave.your_host.com 8083 admin your_passw0rd
+# 
+# example: v-add-remote-dns-host slave.your_host.com 8083 api_key ''
 #
 # The function adds remote dns server to the dns cluster.
+# As alternative api_key generated on the slave server.
+# See v-generate-api-key can be used to connect the remote dns server
 
 
 #----------------------------------------------------------#
@@ -26,8 +33,11 @@ dns_user=${6-dns-cluster}
 DNS_USER=$dns_user
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/remote.sh
 source $HESTIA/func/remote.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -48,7 +58,8 @@ is_password_valid
 is_dnshost_new
 is_dnshost_alive
 
-
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#

+ 8 - 0
bin/v-add-remote-dns-record

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add remote dns domain record
 # options: USER DOMAIN ID
+# labels: dns
+#
+# example: v-add-remote-dns-record bob acme.com 23
 #
 # The function synchronize dns domain with the remote server.
 
@@ -15,8 +18,11 @@ domain=$2
 id=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/remote.sh
 source $HESTIA/func/remote.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -32,6 +38,8 @@ is_object_valid 'dns' 'DOMAIN' "$domain"
 is_procces_running
 remote_dns_health_check
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 10 - 9
bin/v-add-sys-filemanager

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: add file manager functionality to Hestia Control Panel
-# options: none
+# options: [MODE]
+# labels: hestia
 #
 # The function installs the File Manager on the server
 # for access through the Web interface.
@@ -10,16 +11,19 @@
 #----------------------------------------------------------#
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
+# shellcheck source=/usr/local/hestia/install/upgrade/upgrade.conf
+source $HESTIA/install/upgrade/upgrade.conf
 
 MODE=$1
 user="admin"
 
 FM_INSTALL_DIR="$HESTIA/web/fm"
-FM_V="7.4.1"
-FM_FILE="filegator_v${FM_V}.zip"
-FM_URL="https://github.com/filegator/filegator/releases/download/v${FM_V}/${FM_FILE}"
+FM_FILE="filegator_v${fm_v}.zip"
+FM_URL="https://github.com/filegator/filegator/releases/download/v${fm_v}/${FM_FILE}"
 COMPOSER_BIN="$HOMEDIR/$user/.composer/composer"
 
 
@@ -85,6 +89,7 @@ if [ $? -ne 0 ]; then
     # Installation failed, clean up files
     rm --recursive --force ${FM_INSTALL_DIR}
     $BIN/v-change-sys-config-value 'FILE_MANAGER' 'false'
+    $BIN/v-log-action "system" "Error" "Plugins" "File Manager installation failed (Version: $fm_v)."
     exit 1
 fi
 
@@ -100,13 +105,9 @@ chown $user: "${FM_INSTALL_DIR}/repository"
 
 $BIN/v-change-sys-config-value 'FILE_MANAGER' 'true'
 
-if [ "$MODE" != "quiet" ]; then
-    echo "File Manager is now installed and ready for use."  
-fi
-
 #----------------------------------------------------------#
 #                       Logging                            #
 #----------------------------------------------------------#
 
-log_history "file manager installed" '' 'admin'
+$BIN/v-log-action "system" "Info" "Plugins" "File Manager enabled (Version: $fm_v)."
 log_event "$OK" "$ARGUMENTS"

+ 7 - 0
bin/v-add-sys-firewall

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add system firewall
 # options: NONE
+# labels: 
+#
+# example: v-add-sys-firewall
 #
 # The script enables firewall
 
@@ -10,7 +13,9 @@
 #----------------------------------------------------------#
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -22,6 +27,8 @@ if [ "$FIREWALL_SYSTEM" = 'iptables' ]; then
     exit
 fi
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 19 - 5
bin/v-add-sys-ip

@@ -1,11 +1,14 @@
 #!/bin/bash
 # info: add system ip address
-# options: IP NETMASK [INTERFACE] [USER] [IP_STATUS] [IP_NAME] [NAT_IP]
+# options: IP NETMASK [INTERFACE] [USER] [IP_STATUS] [IP_NAME] [NAT_IP] [HELO]
+# labels:
+#
+# example: v-add-sys-ip 216.239.32.21 255.255.255.0
 #
 # The function adds ip address into a system. It also creates rc scripts. You
 # can specify ip name which will be used as root domain for temporary aliases.
 # For example, if you set a1.myhosting.com as name, each new domain created on
-# this  ip will automatically receive alias $domain.a1.myhosting.com. Of course
+# this ip will automatically receive alias $domain.a1.myhosting.com. Of course
 # you must have wildcard record *.a1.myhosting.com pointed to ip. This feature 
 # is very handy when customer wants to test domain before dns migration.
 
@@ -25,11 +28,16 @@ user="${4-admin}"
 ip_status="${5-shared}"
 ip_name=$6
 nat_ip=$7
+helo=$8
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -37,8 +45,8 @@ source $HESTIA/conf/hestia.conf
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '2' "$#" 'IP NETMASK [INTERFACE] [USER] [STATUS] [NAME] [NATED_IP]'
-is_format_valid 'ip' 'netmask' 'interface' 'user' 'ip_status'
+check_args '2' "$#" 'IP NETMASK [INTERFACE] [USER] [STATUS] [NAME] [NATED_IP] [HELO]'
+is_format_valid 'ip' 'netmask' 'iface' 'user' 'ip_status'
 is_ip_free
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
@@ -109,6 +117,7 @@ U_WEB_DOMAINS='0'
 INTERFACE='$iface'
 NETMASK='$netmask'
 NAT='$nat_ip'
+HELO='$helo'
 TIME='$time'
 DATE='$date'" > $HESTIA/data/ips/$ip
 chmod 660 $HESTIA/data/ips/$ip
@@ -210,8 +219,13 @@ if [ ! -z "$FIREWALL_SYSTEM" ]; then
     $BIN/v-update-firewall
 fi
 
+# Update ip helo for exim
+if [ ! -z "$MAIL_SYSTEM" ] && [ ! -z "$helo"]; then
+    $BIN/v-change-sys-ip-helo $ip $helo
+fi
+
 # Logging
-log_history "added system ip address $ip" '' 'admin'
+$BIN/v-log-action "system" "Info" "Network" "Added new IP address to the system (IP: $ip)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 118 - 0
bin/v-add-sys-pma-sso

@@ -0,0 +1,118 @@
+#!/bin/bash
+# info: enables support for single sign on PHPmyAdmin 
+# options: [mode]
+# labels: 
+#
+# example: v-add-sys-pma-sso
+#
+# Enables support for SSO to PHPmyAdmin
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+MODE=$1
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+PMA_INSTALL="/usr/share/phpmyadmin"
+PMA_CONFIG="/etc/phpmyadmin"
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+# Checking root permissions
+if [ "x$(id -u)" != 'x0' ]; then
+    echo "Error: Script can be run executed only by root"
+    exit 10
+fi
+
+if [ ! -z "$PHPMYADMIN_KEY" ] && [ "$PHPMYADMIN_KEY" != "" ] ; then
+    echo "Error: SSO has been installed before to reenable it please run v-delete-sys-pma-sso first"
+    exit 1;
+fi
+
+# Ensure that $HESTIA (/usr/local/hestia/) and other variables are valid.
+if [ -z "$HESTIA" ]; then
+    HESTIA="/usr/local/hestia"
+fi
+
+if [ -z "$HOMEDIR" ] || [ -z "$HESTIA_INSTALL_DIR" ]; then
+    echo "Error: Hestia environment vars not present"
+    exit 2
+fi
+
+if [ -f "/usr/share/phpmyadmin/hestia-sso.php" ]; then 
+    echo "Error: hestia-sso.php is already installed"
+    exit 2
+fi
+
+if [ -f "/usr/local/hesta/web/api/index.php" ]; then 
+    echo "Error: API script not installed"
+    exit 2
+fi
+
+if [ "$API" != "yes" ]; then 
+    echo "Error: API is not enabled"
+    exit 2
+fi
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Generate the keys to secure everything
+phpmyadminkey=$(generate_password);
+apikey=$($BIN/v-generate-api-key);
+
+# copy config dir to /usr/share/phpmyadmin/
+cp -f $HESTIA_INSTALL_DIR/phpmyadmin/hestia-sso.php $PMA_INSTALL/hestia-sso.php
+chmod 644 $PMA_INSTALL/hestia-sso.php 
+
+sed -i "s/%PHPMYADMIN_KEY%/$phpmyadminkey/g" $PMA_INSTALL/hestia-sso.php 
+sed -i "s/%API_KEY%/$apikey/g" $PMA_INSTALL/hestia-sso.php 
+sed -i "s/%API_HOST_NAME%/$(hostname)/g" $PMA_INSTALL/hestia-sso.php 
+sed -i "s/%API_HESTIA_PORT%/$BACKEND_PORT/g" $PMA_INSTALL/hestia-sso.php 
+
+
+# Check if config already contains the keys 
+
+touch $PMA_CONFIG/hestia-sso.inc.php
+chmod 644 $PMA_CONFIG/hestia-sso.inc.php
+echo "<?php
+if(isset(\$_GET['hestia_token']) || isset(\$_COOKIE['SignonSession'])){
+\$cfg['Servers'][\$i]['auth_type'] = 'signon';
+\$cfg['Servers'][\$i]['SignonSession'] = 'SignonSession';
+\$cfg['Servers'][\$i]['SignonURL'] = 'hestia-sso.php';
+\$cfg['Servers'][\$i]['LogoutURL'] = 'hestia-sso.php?logout=1';
+}
+?>" >> $PMA_CONFIG/hestia-sso.inc.php
+
+file=$(cat $PMA_CONFIG/config.inc.php)
+if ! [[  $file =~ "hestia-sso.inc.php" ]]; then 
+    if [[ $file =~ "//Add Hestia SSO code here" ]]; then 
+        sed -i "s|//Add Hestia SSO code here|//Add Hestia SSO code here\n     include ('$PMA_CONFIG/hestia-sso.inc.php');|g" $PMA_CONFIG/config.inc.php
+    else
+        echo "include ('$PMA_CONFIG/hestia-sso.inc.php');" >> $PMA_CONFIG/config.inc.php    
+    fi
+fi
+
+$BIN/v-change-sys-config-value 'PHPMYADMIN_KEY' "$phpmyadminkey"
+
+#----------------------------------------------------------#
+#                       Logging                            #
+#----------------------------------------------------------#
+
+if [ "$MODE" != "quiet" ]; then
+    echo "PMA Hestia-SSO plugin has been succesfully installed"
+fi
+$BIN/v-log-action "system" "Info" "Plugins" "phpMyAdmin Single Sign-On has been enabled."
+log_event "$OK" "$ARGUMENTS"

+ 9 - 1
bin/v-add-sys-quota

@@ -1,8 +1,12 @@
 #!/bin/bash
 # info: add system quota
 # options: NONE
+# labels: 
+#
+# example: v-add-sys-quota
 #
 # The script enables filesystem quota on /home partition
+# Some kernels do require additional packages to be installed first
 
 
 #----------------------------------------------------------#
@@ -10,7 +14,9 @@
 #----------------------------------------------------------#
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -42,7 +48,8 @@ if [ $? -ne 0 ]; then
     fi
 fi
 
-
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#
@@ -96,6 +103,7 @@ done
 #----------------------------------------------------------#
 
 # Logging
+$BIN/v-log-action "system" "Info" "Plugins" "System Quota enforcement enabled."
 log_history "system quota enforcement enabled"
 log_event "$OK" "$ARGUMENTS"
 

+ 177 - 0
bin/v-add-sys-rainloop

@@ -0,0 +1,177 @@
+#!/bin/bash
+# info: Install Rainloop in HestiaCP
+# options: [MODE]
+# labels: hestia
+#
+# The function installs Rainloop
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+# shellcheck source=/usr/local/hestia/install/upgrade/upgrade.conf
+source $HESTIA/install/upgrade/upgrade.conf
+
+MODE=$1
+UPDATE="no"
+# Version and Download paths
+# Version to be moved to upgrade script
+RL_FILE="rainloop-community-latest.zip"
+# For removal of folder
+RL_EXTRACT_MAIN="rainloop"
+
+# Downloading full version
+RL_URL="https://www.rainloop.net/repository/webmail/rainloop-community-latest.zip"
+
+# Folder paths
+RL_INSTALL_DIR="/var/lib/rainloop"
+RL_CONFIG_DIR="/etc/rainloop"
+RL_LOG="/var/log/rainloop"
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+# Checking root permissions
+if [ "x$(id -u)" != 'x0' ]; then
+    echo "ERROR: v-add-sys-rainloop can be run executed only by root user"
+    exit 10
+fi
+
+# Ensure that $HESTIA (/usr/local/hestia/) and other variables are valid.
+if [ -z "$HESTIA" ]; then
+    HESTIA="/usr/local/hestia"
+fi
+
+if [ -z "$HOMEDIR" ] || [ -z "$HESTIA_INSTALL_DIR" ]; then
+    echo "ERROR: Environment variables not present, installation aborted."
+    exit 2
+fi
+
+# Get current version 
+if [ -f "/var/lib/rainloop/data/VERSION" ]; then
+    version=$(cat $RL_INSTALL_DIR/data/VERSION);
+    if [ "$version" == "$rl_v" ]; then
+        echo "Error: Installed version ($version) is equal as the availble version ($rl_v)"
+        exit 2;
+    else 
+        UPDATE="yes"
+    fi
+fi
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+if [ "$UPDATE" == "no" ]; then
+    rm -f -r $RL_INSTALL_DIR
+    rm -f -r $RL_CONFIG_DIR
+
+    mkdir $RL_INSTALL_DIR
+    mkdir $RL_CONFIG_DIR
+    
+    cd "$RL_INSTALL_DIR"
+    [ ! -f "${RC_INSTALL_DIR}/${RC_FILE}" ] && wget "$RL_URL" --retry-connrefused --quiet -O "${RL_INSTALL_DIR}/${RL_FILE}"
+    
+    key=$(openssl rand -hex 4);
+    
+    admin_account="admin_$key"
+    admin_password=$(generate_password)
+    r=$(generate_password)
+
+    echo "Username: admin_$key" > ~/.rainloop
+    echo "Password: $admin_password" >> ~/.rainloop
+    echo "Secret key: admin_$key" >> ~/.rainloop
+    
+    unzip -q ${RL_INSTALL_DIR}/${RL_FILE}
+    
+    mv ./data $RL_CONFIG_DIR/
+    ln -s $RL_CONFIG_DIR/data/ ./data
+
+    SALT=$(openssl rand -base64 64)
+    cp ./data/VERSION ./data/INSTALLED
+    echo "<?php //$SALT" >  ./data/SALT.php
+    echo "Forbidden" >  ./data/index.php
+    echo "Forbidden" >  ./data/index.html
+
+    # Create database
+    mysql -e "CREATE DATABASE rainloop"
+    # Mysql available on system
+    r=$(generate_password)
+    mysql -e "GRANT ALL ON rainloop.*
+     TO rainloop@localhost IDENTIFIED BY '$r'"
+
+    mkdir -p $RL_CONFIG_DIR/data/_data_/_default_/configs
+    php -f $HESTIA_INSTALL_DIR/rainloop/change_password.php "admin_$key" "$admin_password" "$r"
+    mkdir -p $RL_CONFIG_DIR/data/_data_/_default_/domains
+    cp -f $HESTIA_INSTALL_DIR/rainloop/default.ini $RL_CONFIG_DIR/data/_data_/_default_/domains
+    mkdir -p $RL_CONFIG_DIR/data/_data_/_default_/plugins
+    cp -f -r $HESTIA_INSTALL_DIR/rainloop/plugins/hestia-change-password/ $RL_CONFIG_DIR/data/_data_/_default_/plugins
+    mkdir -p $RL_CONFIG_DIR/data/_data_/_default_/plugins/add-x-originating-ip-header
+    # Download add-x-originating-ip-header from rainloop github
+    wget --quiet -O $RL_CONFIG_DIR/data/_data_/_default_/plugins/add-x-originating-ip-header/index.php https://raw.githubusercontent.com/RainLoop/rainloop-webmail/master/plugins/add-x-originating-ip-header/index.php
+    wget --quiet -O $RL_CONFIG_DIR/data/_data_/_default_/plugins/add-x-originating-ip-header/VERSION https://raw.githubusercontent.com/RainLoop/rainloop-webmail/master/plugins/add-x-originating-ip-header/VERSION
+    wget --quiet -O $RL_CONFIG_DIR/data/_data_/_default_/plugins/add-x-originating-ip-header/README https://raw.githubusercontent.com/RainLoop/rainloop-webmail/master/plugins/add-x-originating-ip-header/README
+    wget --quiet -O $RL_CONFIG_DIR/data/_data_/_default_/plugins/add-x-originating-ip-header/LICENSE https://raw.githubusercontent.com/RainLoop/rainloop-webmail/master/plugins/add-x-originating-ip-header/LICENSE
+    
+    cp -f $HESTIA_INSTALL_DIR/rainloop/plugins/plugin-add-x-originating-ip-header.ini $RL_CONFIG_DIR/data/_data_/_default_/configs/plugin-add-x-originating-ip-header.ini
+    cp -f $HESTIA_INSTALL_DIR/rainloop/plugins/plugin-hestia-change-password.ini $RL_CONFIG_DIR/data/_data_/_default_/configs/plugin-hestia-change-password.ini
+    
+    sed -i "s/%hostname%/$(hostname)/g" $RL_CONFIG_DIR/data/_data_/_default_/configs/plugin-hestia-change-password.ini
+    sed -i "s/%port%/$BACKEND_PORT/g" $RL_CONFIG_DIR/data/_data_/_default_/configs/plugin-hestia-change-password.ini
+    
+    
+    chown -R  www-data:www-data ./data
+    chown -R  www-data:www-data $RL_CONFIG_DIR/
+    
+    rm  ${RL_INSTALL_DIR}/${RL_FILE}  
+    # Add robots.txt
+    echo "User-agent: *" > $RL_INSTALL_DIR/robots.txt
+    echo "Disallow: /" >> $RL_INSTALL_DIR/robots.txt
+    
+    # Updating hestia.conf
+    if [ -z "$(grep WEBMAIL_SYSTEM $HESTIA/conf/hestia.conf)" ]; then
+        $BIN/v-change-sys-config-value 'WEBMAIL_SYSTEM' 'rainloop'
+    else
+        if [  -z "$(echo "$WEBMAIL_SYSTEM" | grep -w 'rainloop')" ]; then
+           if [ ! -z "$WEBMAIL_SYSTEM" ]; then
+               $BIN/v-change-sys-config-value 'WEBMAIL_SYSTEM' "rainloop,$WEBMAIL_SYSTEM"
+           else
+               $BIN/v-change-sys-config-value 'WEBMAIL_SYSTEM' "rainloop"
+           fi
+        fi
+    fi
+
+else
+   [ ! -f "${RC_INSTALL_DIR}/${RC_FILE}" ] && wget "$RL_URL" --quiet -O "${RL_INSTALL_DIR}/${RL_FILE}"
+   version=$(cat $RL_INSTALL_DIR/data/VERSION);
+   
+   unzip -q -j rainloop-community-latest.zip "data/VERSION" -d $RL_INSTALL_DIR/ 
+   version_source=$(cat $RL_INSTALL_DIR/VERSION);
+   
+   # Check version inside .zip file in case hestia didn't update yet
+   if [ "$version" != "$version_source" ]; then 
+       unzip -q ${RL_INSTALL_DIR}/${RL_FILE}
+       rm $RL_INSTALL_DIR/$RL_FILE
+    fi
+    rm ${RL_INSTALL_DIR}/VERSION
+fi
+
+#----------------------------------------------------------#
+#                       Logging                            #
+#----------------------------------------------------------#
+
+if [ "$UPDATE" = "yes" ]; then
+    $BIN/v-log-action "system" "Info" "Plugins" "Rainloop updated (Version: $version)."
+else
+    $BIN/v-log-action "system" "Info" "Plugins" "Rainloop enabled (Version: $version)."
+fi
+log_event "$OK" "$ARGUMENTS"

+ 199 - 0
bin/v-add-sys-roundcube

@@ -0,0 +1,199 @@
+#!/bin/bash
+# info: Install RoundCube for Nginx/Apache2 
+# options: [MODE]
+# labels: hestia
+#
+# The function installs Round Cube
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+# shellcheck source=/usr/local/hestia/install/upgrade/upgrade.conf
+source $HESTIA/install/upgrade/upgrade.conf
+
+MODE=$2
+UPDATE="no"
+# Version and Download paths
+RC_FILE="roundcubemail-$rc_v-complete.tar.gz"
+RC_EXTRACT="roundcubemail-$rc_v"
+# Downloading full version
+RC_URL="https://github.com/roundcube/roundcubemail/releases/download/$rc_v/roundcubemail-$rc_v-complete.tar.gz"
+
+# Folder paths
+RC_INSTALL_DIR="/var/lib/roundcube"
+RC_CONFIG_DIR="/etc/roundcube"
+RC_LOG="/var/log/roundcube"
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+# Checking root permissions
+if [ "x$(id -u)" != 'x0' ]; then
+    echo "ERROR: v-add-sys-roundcube can be run executed only by root user"
+    exit 10
+fi
+
+# Ensure that $HESTIA (/usr/local/hestia/) and other variables are valid.
+if [ -z "$HESTIA" ]; then
+    HESTIA="/usr/local/hestia"
+fi
+
+if [ -z "$HOMEDIR" ] || [ -z "$HESTIA_INSTALL_DIR" ]; then
+    echo "ERROR: Environment variables not present, installation aborted."
+    exit 2
+fi
+
+if [ -z "$(echo "$DB_SYSTEM" | grep -w 'mysql')" ]; then
+    echo "ERROR: Mysql not available. Installation aborted"
+    exit 2
+fi
+
+if [ -d "/usr/share/roundcube" ]; then
+    echo "ERROR: Install done from apt source, unable to continue"
+    exit 2;
+fi
+
+# Get current version 
+if [ -f "/var/lib/roundcube/index.php" ]; then
+    version=$(cat $RC_INSTALL_DIR/index.php | grep -o -E '[0-9].[0-9].[0-9]+' | head -1);
+    if [ "$version" == "$rc_v" ]; then
+        echo "Error: Installed version ($version) is equal to the available version ($rc_v)"
+        exit 2;
+    else 
+        UPDATE="yes"
+    fi
+fi
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+if [ "$UPDATE" == "no" ]; then
+    rm  -f -r $RC_INSTALL_DIR
+    rm  -f -r $RC_CONFIG_DIR
+    
+    mkdir -p $RC_INSTALL_DIR/
+    mkdir -p $RC_CONFIG_DIR/
+    
+    cd "$RC_INSTALL_DIR"
+    [ ! -f "${RC_INSTALL_DIR}/${RC_FILE}" ] && wget "$RC_URL" --retry-connrefused --quiet -O "${RC_INSTALL_DIR}/${RC_FILE}"
+    
+    tar xzf $RC_FILE
+    cp -rf $RC_EXTRACT/* $RC_INSTALL_DIR
+    
+    # Delete old config folder
+    cp $RC_INSTALL_DIR/config/defaults.inc.php $RC_CONFIG_DIR/defaults.inc.php
+    rm -f -r $RC_INSTALL_DIR/config/
+    ln -s $RC_CONFIG_DIR/ ./config
+    # Replace with Hestia config
+    cp -f $HESTIA_INSTALL_DIR/roundcube/main.inc.php $RC_CONFIG_DIR/config.inc.php
+    cp -f $HESTIA_INSTALL_DIR/roundcube/mimetypes.php $RC_CONFIG_DIR/mimetypes.php
+    
+    cp -f $HESTIA_INSTALL_DIR/roundcube/hestia.php $RC_INSTALL_DIR/plugins/password/drivers/
+    mkdir -p $RC_CONFIG_DIR/plugins/password
+    mkdir -p $RC_CONFIG_DIR/plugins/newmail_notifier
+    mkdir -p $RC_CONFIG_DIR/plugins/zipdownload
+    
+    # Allow changes to the respective config / Create symlinks to /etc/roundcube/ 
+    cp -f $HESTIA_INSTALL_DIR/roundcube/config.inc.php $RC_CONFIG_DIR/plugins/password/config.inc.php
+    ln -s $RC_CONFIG_DIR/plugins/password/config.inc.php ./plugins/password/config.inc.php
+    cp -f $HESTIA_INSTALL_DIR/roundcube/plugins/config_newmail_notifier.inc.php $RC_CONFIG_DIR/plugins/newmail_notifier/config.inc.php
+    ln -s $RC_CONFIG_DIR/plugins/newmail_notifier/config.inc.php ./plugins/newmail_notifier/config.inc.php
+    cp -f $HESTIA_INSTALL_DIR/roundcube/plugins/config_zipdownload.inc.php $RC_CONFIG_DIR/plugins/zipdownload/config.inc.php
+    ln -s $RC_CONFIG_DIR/plugins/zipdownload/config.inc.php ./plugins/zipdownload/config.inc.php
+    
+    
+    chmod 640 $RC_CONFIG_DIR/config.inc.php
+    chown root:www-data $RC_CONFIG_DIR/config.inc.php
+    
+    # Log file 
+    if [ ! -d  $RC_LOG ];then
+        mkdir $RC_LOG
+    fi
+    chown www-data:root $RC_LOG
+    chmod 751 $RC_LOG
+    
+    if [ ! -z "$(echo "$DB_SYSTEM" | grep -w 'mysql')" ]; then
+        mysql -e "DROP DATABASE IF EXISTS roundcube"
+        mysql -e "DROP USER IF EXISTS roundcube@localhost"
+        mysql -e "CREATE DATABASE roundcube"
+        # Mysql available on system
+        r=$(generate_password)
+        mysql -e "GRANT ALL ON roundcube.*
+         TO roundcube@localhost IDENTIFIED BY '$r'"
+        sed -i "s/%password%/$r/g" $RC_CONFIG_DIR/config.inc.php
+        mysql roundcube < /var/lib/roundcube/SQL/mysql.initial.sql
+    fi
+    # To do in future add support for Postgresql only setup
+    
+    rcDesKey="$(openssl rand -base64 30 | tr -d "/" | cut -c1-24)"
+    sed -i "s/%des_key%/$rcDesKey/g" $RC_CONFIG_DIR/config.inc.php
+    # Change hostname for password change
+    sed -i "s/localhost/$(hostname)/g" $RC_CONFIG_DIR/plugins/password/config.inc.php
+    
+    #Clean up
+    rm -f -r $RC_INSTALL_DIR/installer;
+    rm -f -r $RC_INSTALL_DIR/$RC_FILE;
+    rm -f -r $RC_INSTALL_DIR/$RC_EXTRACT;
+    
+    # Add robots.txt
+    echo "User-agent: *" > /var/lib/roundcube/robots.txt
+    echo "Disallow: /" >> /var/lib/roundcube/robots.txt
+    
+    # Updating hestia.conf
+    if [ -z "$(grep WEBMAIL_SYSTEM $HESTIA/conf/hestia.conf)" ]; then
+        $BIN/v-change-sys-config-value 'WEBMAIL_SYSTEM' 'roundcube'
+    else
+        if [  -z "$(echo "$WEBMAIL_SYSTEM" | grep -w 'roundcube')" ]; then
+           if [ ! -z "$WEBMAIL_SYSTEM" ]; then
+               $BIN/v-change-sys-config-value 'WEBMAIL_SYSTEM' "roundcube,$WEBMAIL_SYSTEM"
+           else
+               $BIN/v-change-sys-config-value 'WEBMAIL_SYSTEM' "roundcube"
+           fi
+        fi
+    fi
+    
+    phpenmod mcrypt > /dev/null 2>&1
+else
+    rm  -f -r $RC_INSTALL_DIR
+    mkdir $RC_INSTALL_DIR
+    cd "$RC_INSTALL_DIR"
+    [ ! -f "${RC_INSTALL_DIR}/${RC_FILE}" ] && wget "$RC_URL" --quiet -O "${RC_INSTALL_DIR}/${RC_FILE}"
+    
+    tar xzf $RC_FILE
+    cp -rf $RC_EXTRACT/* $RC_INSTALL_DIR
+    
+    cp -f $RC_INSTALL_DIR/config/defaults.inc.php $RC_CONFIG_DIR/defaults.inc.php
+    rm -f -r $RC_INSTALL_DIR/config/
+    ln -s $RC_CONFIG_DIR/ ./config
+
+    ln -s $RC_CONFIG_DIR/plugins/password/config.inc.php ./plugins/password/config.inc.php
+    ln -s $RC_CONFIG_DIR/plugins/newmail_notifier/config.inc.php ./plugins/newmail_notifier/config.inc.php
+    ln -s $RC_CONFIG_DIR/plugins/zipdownload/config.inc.php ./plugins/zipdownload/config.inc.php  
+    
+    $RC_INSTALL_DIR/bin/update.sh --version "$version"
+        
+    rm -f -r $RC_INSTALL_DIR/installer;
+    rm -f -r $RC_INSTALL_DIR/$RC_FILE;
+    rm -f -r $RC_INSTALL_DIR/$RC_EXTRACT;  
+fi
+#----------------------------------------------------------#
+#                       Logging                            #
+#----------------------------------------------------------#
+
+if [ "$UPDATE" = "yes" ]; then
+    $BIN/v-log-action "system" "Info" "Plugins" "Roundcube updated (Version: $version)."
+else
+    $BIN/v-log-action "system" "Info" "Plugins" "Roundcube enabled (Version: $version)."
+fi
+log_event "$OK" "$ARGUMENTS"

+ 7 - 0
bin/v-add-sys-sftp-jail

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add system sftp jail
 # options: [RESTART]
+# labels: 
+#
+# example: v-add-sys-sftp-jail yes
 #
 # The script enables sftp jailed environment
 
@@ -11,7 +14,9 @@
 
 # Includes
 source /etc/profile
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 restart=$1
@@ -20,6 +25,8 @@ restart=$1
 #                    Verifications                         #
 #----------------------------------------------------------#
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 63 - 0
bin/v-add-sys-smtp-relay

@@ -0,0 +1,63 @@
+#!/bin/bash
+# info: add system wide smtp relay support
+# options: HOST USERNAME PASSWORD [PORT]
+# labels: hestia
+#
+# example: v-add-sys-smtp-relay srv.smtprelay.tld uname123 pass12345
+#
+# this function adds system wide smtp relay support.
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+host=$1
+username=$2
+password=$3
+port=${4-587}
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '3' "$#" 'HOST USERNAME PASSWORD'
+is_format_valid 'port'
+is_system_enabled "$MAIL_SYSTEM" 'MAIL_SYSTEM'
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+
+$BIN/v-change-sys-config-value SMTP_RELAY 'true'
+$BIN/v-change-sys-config-value SMTP_RELAY_HOST $host
+$BIN/v-change-sys-config-value SMTP_RELAY_PORT $port
+$BIN/v-change-sys-config-value SMTP_RELAY_USER $username
+
+cat >/etc/exim4/smtp_relay.conf << EOL
+host:$host
+port:$port
+user:$username
+pass:$password
+EOL
+
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Logging
+$BIN/v-log-action "system" "Info" "Mail" "Server-wide SMTP Relay enabled (Host: $host, Port: $port)."
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 0 - 90
bin/v-add-sys-theme

@@ -1,90 +0,0 @@
-#!/bin/bash
-# info: install theme from local source or GitHub.
-# options: theme [MODE] [ACTIVE]
-
-# The function for installing a custom theme or downloading one
-# from the HestiaCP theme repository.
-
-#----------------------------------------------------------#
-#                    Variable&Function                     #
-#----------------------------------------------------------#
-
-# Argument definition
-theme=$1
-mode=$2
-active=$3
-
-# Includes
-source $HESTIA/func/main.sh
-source $HESTIA/conf/hestia.conf
-
-# Define themes repository URL format
-HESTIA_THEMES_REPO="$HESTIA_GIT_REPO/$RELEASE_BRANCH/install/deb/themes"
-
-#----------------------------------------------------------#
-#                       Action                             #
-#----------------------------------------------------------#
-
-# Fallback to downloading from GitHub if no mode specified
-if [ -z "$mode" ]; then
-    mode="git"
-fi
-
-# Initialize local directory if it does not exist
-if [ ! -d "$HESTIA_THEMES_CUSTOM" ]; then
-    mkdir -p $HESTIA_THEMES_CUSTOM
-fi
-
-# Abort if no theme name specified
-if [ -z "$theme" ]; then
-    echo "ERROR: No theme name specified."
-    echo "Usage: v-add-sys-theme theme [GIT | LOCAL] [ACTIVE]"
-    echo "       theme: name of the theme to install."
-    echo "       active: Set downloaded theme as active (optional)"
-
-    exit 1
-fi
-
-# Check if theme name already exists as system theme
-if [ -e $HESTIA_THEMES/$theme.css ]; then
-    echo "ERROR: System theme with the same name already exists: $theme."
-    exit 1
-fi
-
-# Prompt to replace existing theme if detected
-if [ -e $HESTIA_THEMES_CUSTOM/$theme.css ]; then
-    echo "WARNING: Theme file $theme.css already exists."
-    read -p "Would you like to replace it? [Y/N] " replace_theme
-
-    if [ "$replace_theme" = "N" ] || [ "$replace_theme" = "n" ]; then
-        exit 1
-    fi
-fi
-
-# Install theme from GitHub repository
-if [ "$mode" = "git" ]; then
-    # Check if it's a valid file first
-    theme_check=$(curl -s --head -w %{http_code} $HESTIA_THEMES_REPO/$theme.css -o /dev/null)
-    if [ $theme_check -ne "200" ]; then
-        echo "Error: invalid theme name specified."
-        exit 1
-    fi
-
-    # Download the theme file from Git
-    echo "Downloading and installing theme: $theme..."
-    wget $HESTIA_THEMES_REPO/$theme.css -O $HESTIA_THEMES_CUSTOM/$theme.css > /dev/null 2>&1
-fi
-
-if [ "$mode" = "local" ]; then
-    read -p "Please enter the full path to the CSS file to import: " theme_path
-    cp -f $theme_path $HESTIA_THEMES_CUSTOM/
-fi
-
-# Set active theme
-$BIN/v-change-sys-theme $theme
-
-#----------------------------------------------------------#
-#                       Hestia                             #
-#----------------------------------------------------------#
-
-exit

+ 19 - 3
bin/v-add-user

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add system user
-# options: USER PASSWORD EMAIL [PACKAGE] [NAME]
+# options: USER PASSWORD EMAIL [PACKAGE] [NAME] [LASTNAME]
+# labels: 
+#
+# example: v-add-user admin2 P4$$w@rD [email protected]
 #
 # The function creates new user account.
 
@@ -15,9 +18,14 @@ password=$2; HIDE=2
 email=$3
 package=${4-default}
 name=$5
-
+# Last name has been added for backward compatibility with WHMCS / Blesta VestaCP Plugins
+if [ ! -z "$6" ]; then 
+    name="$name $6";
+fi
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 is_user_free() {
@@ -109,6 +117,7 @@ mkdir $HOMEDIR/$user/.config \
       $HOMEDIR/$user/.cache \
       $HOMEDIR/$user/.local \
       $HOMEDIR/$user/.composer \
+      $HOMEDIR/$user/.vscode-server \
       $HOMEDIR/$user/.ssh \
       $HOMEDIR/$user/.npm
 
@@ -117,6 +126,7 @@ chown $user:$user \
       $HOMEDIR/$user/.cache \
       $HOMEDIR/$user/.local \
       $HOMEDIR/$user/.composer \
+      $HOMEDIR/$user/.vscode-server \
       $HOMEDIR/$user/.ssh \
       $HOMEDIR/$user/.npm
 
@@ -225,7 +235,12 @@ U_DATABASES='0'
 U_CRON_JOBS='0'
 U_BACKUPS='0'
 LANGUAGE=''
+THEME=''
 NOTIFICATIONS='no'
+PREF_UI_SORT='name'
+LOGIN_DISABLED='no'
+LOGIN_USE_IPLIST='no'
+LOGIN_ALLOW_IPS=''
 TIME='$time'
 DATE='$date'" > $USER_DATA/user.conf
 chmod 660 $USER_DATA/user.conf
@@ -249,7 +264,8 @@ fi
 $BIN/v-add-user-sftp-jail $user
 
 # Logging
-log_history "added system user $user" '' 'admin'
+$BIN/v-log-action "system" "Info" "Users" "User account added (Name: $user)."
+$BIN/v-log-action "$user" "Info" "System" "Welcome!"
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 5 - 0
bin/v-add-user-2fa

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add 2fa to existing user
 # options: USER
+# labels: hestia panel
+#
+# example: v-add-user-2fa admin
 #
 # The function creates a new 2fa token for user.
 
@@ -13,7 +16,9 @@
 user=$1
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 

+ 10 - 2
bin/v-add-user-composer

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add composer (php dependency manager) for a user
 # options: USER
+# labels: hestia
+#
+# example: v-add-user-composer user
 #
 # The function adds support for composer (php dependency manager)
 # Homepage: https://getcomposer.org/
@@ -16,7 +19,12 @@ user=$1
 if [ -z "$HESTIA" ]; then
     HESTIA="/usr/local/hestia"
 fi
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
 
 
 #----------------------------------------------------------#
@@ -70,14 +78,14 @@ if [[ "$signature" != $(sha384sum $COMPOSER_SETUP_FILE | cut -f 1 -d " ") ]]; th
     check_result $E_INVALID "Composer signature does not match"
 fi
 
-COMPOSER_HOME="$HOMEDIR/$user/.config/composer" user_exec /usr/bin/php "$COMPOSER_SETUP_FILE" --quiet --install-dir="$COMPOSER_DIR" --filename=composer
+COMPOSER_HOME="$HOMEDIR/$user/.config/composer" user_exec /usr/bin/php "$COMPOSER_SETUP_FILE" --1 --quiet --install-dir="$COMPOSER_DIR" --filename=composer
 check_result $? "Composer install failed"
 
 [ -f "$COMPOSER_SETUP_FILE" ] && rm -f "$COMPOSER_SETUP_FILE"
 
 
 # Logging
-log_history "Enabled composer for user $user"
+$BIN/v-log-action "$user" "Info" "Plugins" "Composer support enabled."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 5 - 1
bin/v-add-user-notification

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: add user notification
 # options: USER TOPIC NOTICE [TYPE]
+# labels: 
 #
 # The function adds user notification.
 
@@ -16,7 +17,9 @@ notice=$(echo $3 |sed "s/'/%quote%/g")
 type=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -28,7 +31,8 @@ check_args '2' "$#" 'USER TOPIC NOTICE [TYPE]'
 is_format_valid 'user' 'topic' 'notice'
 is_object_valid 'user' 'USER' "$user"
 
-
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#

+ 5 - 2
bin/v-add-user-package

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: adding user package
 # options: PKG_DIR PACKAGE [REWRITE]
+# labels: 
 #
 # The function adds new user package to the system.
 
@@ -15,7 +16,9 @@ package=$2
 rewrite=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Functions
@@ -96,9 +99,9 @@ chmod 644 $HESTIA/data/packages/$package.pkg
 
 # Logging
 if [ "$rewrite" != 'yes' ]; then
-    log_history "added user package $package" '' 'admin'
+    $BIN/v-log-action "system" "Info" "Packages" "Package added (Name: $package)."
 else
-    log_history "updated user package $package" '' 'admin'
+    $BIN/v-log-action "system" "Info" "Packages" "Package limits updated (Name: $package)."
 fi
 log_event "$OK" "$ARGUMENTS"
 

+ 8 - 0
bin/v-add-user-sftp-jail

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add user sftp jail
 # options: USER [RESTART]
+# labels: 
+#
+# example: v-add-user-sftp-jail admin
 #
 # The script enables sftp jailed environment
 
@@ -14,7 +17,9 @@ user=$1
 restart=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -46,6 +51,9 @@ if [[ " ${users[@]} " =~ " ${user} " ]]; then
     exit;
 fi
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#

+ 5 - 0
bin/v-add-user-sftp-key

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: add user sftp key
 # options: USER [TTL]
+# labels: hestia
 #
 # The script creates and updates ssh key for filemanager usage
 
@@ -14,7 +15,9 @@ user=$1
 ttl=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -26,6 +29,8 @@ check_args '1' "$#" 'USER [TTL]'
 is_format_valid 'user' 'ttl'
 is_object_valid 'user' 'USER' "$user"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #

+ 8 - 3
bin/v-add-user-ssh-key

@@ -1,8 +1,11 @@
 #!/bin/bash
 # info: add ssh key
-# options: USER key
+# options: USER KEY
+# labels: hestia
 #
-# Function check if $user/.ssh/authorized_keys exists and create it
+# example: v-add-user-ssh-key user 'valid ssh key'
+#
+# Function check if $user/.ssh/authorized_keys exists and create it.
 # After that it append the new key(s)
 
 #----------------------------------------------------------#
@@ -15,7 +18,9 @@ user=$1
 key=$2
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -64,7 +69,7 @@ echo "$key" >> "$AUTHKEY_FILE"
 #----------------------------------------------------------#
 
 # Logging
-log_history "Added ssh-key $user"
+$BIN/v-log-action "$user" "Info" "System" "Added a new SSH key."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 74 - 0
bin/v-add-user-wp-cli

@@ -0,0 +1,74 @@
+#!/bin/bash
+# info: add wp-cli for a user
+# options: USER
+# labels: hestia
+#
+# example: v-add-user-wp-cli user
+#
+# The function adds support for wp-cli to the user account
+
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+
+if [ -z "$HESTIA" ]; then
+    HESTIA="/usr/local/hestia"
+fi
+
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '1' "$#" 'USER'
+is_format_valid 'user'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+
+[ -z "$HOMEDIR" ] && check_result $E_NOTEXIST "Hestia environment vars not present"
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+WPCLI_DIR="/home/$user/.wp"
+WPCLI_BIN="$WPCLI_DIR/wp"
+WPCLICACHE_DIR="/home/$user/.wp-cli"
+
+if [ -f "$WPCLI_DIR" ]; then
+    echo "WP-CLI already available"
+    exit
+fi
+
+[ -z "$(readlink -m "$WPCLI_DIR" | egrep "^$HOMEDIR/$user/")" ] && check_result $E_FORBIDEN "Path outside of user homedir (WP Cli dir)"
+[ -z "$(readlink -m "$WPCLI_BIN" | egrep "^$HOMEDIR/$user/")" ] && check_result $E_FORBIDEN "Path outside of user homedir (WP Cli bin)"
+
+mkdir -p "$WPCLI_DIR"
+chown $user:$user "$WPCLI_DIR"
+
+user_exec wget --tries=3 --timeout=15 --read-timeout=15 --waitretry=3 --no-dns-cache --quiet -O $WPCLI_BIN https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar 
+user_exec chmod +x $WPCLI_BIN
+
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+# Logging
+$BIN/v-log-action "$user" "Info" "Plugins" "WP-CLI support enabled."
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 40 - 10
bin/v-add-web-domain

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add web domain
-# options: USER DOMAIN [IP] [ALIASES] [PROXY_EXTENSIONS] [RESTART]
+# options: USER DOMAIN [IP] [RESTART] [ALIASES] [PROXY_EXTENSIONS]
+# labels: web
+#
+# example: v-add-web-domain admin wonderland.com 192.18.22.43 yes www.wonderland.com
 #
 # The function adds virtual host to a server. In cases when ip is
 # undefined in the script, "default" template will be used. The alias of
@@ -25,15 +28,20 @@ aliases=$5
 proxy_ext=$6
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
 format_domain
 format_domain_idn
 format_aliases
+domain_utf=$(idn -t --quiet -u "$domain_idn")
 
 #----------------------------------------------------------#
 #                    Verifications                         #
@@ -44,10 +52,31 @@ check_args '2' "$#" 'USER DOMAIN [IP] [RESTART] [ALIASES] [PROXY_EXTENSIONS]'
 is_format_valid 'user' 'domain' 'aliases' 'ip' 'proxy_ext'
 is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
-is_package_full 'WEB_DOMAINS' 'WEB_ALIASES'
-is_domain_new 'web' "$domain,$aliases"
+is_package_full 'WEB_DOMAINS' 
+
+if [ "$aliases" != "none" ]; then 
+    ALIAS=$aliases
+    is_package_full 'WEB_ALIASES' 
+fi
+
+if [ "$($BIN/v-list-web-domain $user $domain_utf plain |cut -f 1) " != "$domain" ]; then
+    is_domain_new 'web' "$domain_utf,$aliases"
+fi
+if [ "$($BIN/v-list-web-domain $user $domain_idn plain |cut -f 1) " != "$domain" ]; then
+    is_domain_new 'web' "$domain_idn,$aliases"
+else
+    is_domain_new 'web' "$domain,$aliases"
+fi
+if [ -z "$(is_ip_format_valid $domain)" ]; then
+    echo "Error: Invalid domain format. IP address detected as input." 
+    exit 1
+fi
+
 is_dir_symlink "$HOMEDIR/$user/web"
 is_dir_symlink "$HOMEDIR/$user/web/$domain"
+
+is_base_domain_owner "$domain,$aliases"
+
 if [ ! -z "$ip" ]; then
     is_ip_valid "$ip" "$user"
 else
@@ -65,10 +94,11 @@ check_hestia_demo_mode
 # Reading user values
 source $USER_DATA/user.conf
 
+[[ -e "$HOMEDIR/$user/web/$domain" ]] && check_result $E_EXISTS "Web domain folder for $domain should not exist"
+
 # Creating domain directories
 $BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain"
 $BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/public_html"
-$BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/public_shtml"
 $BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/document_errors"
 $BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/cgi-bin"
 $BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/private"
@@ -92,12 +122,12 @@ done
 chown -R $user:$user $HOMEDIR/$user/web/$domain
 chown root:$user /var/log/$WEB_SYSTEM/domains/$domain.* $conf
 chmod 640 /var/log/$WEB_SYSTEM/domains/$domain.*
-chmod 751 $HOMEDIR/$user/web/$domain $HOMEDIR/$user/web/$domain/*
-chmod 551 $HOMEDIR/$user/web/$domain/stats $HOMEDIR/$user/web/$domain/logs
-chmod 644 $HOMEDIR/$user/web/$domain/public_*html/*
-chown $user:www-data $HOMEDIR/$user/web/$domain/public_*html
+user_exec chmod 751 $HOMEDIR/$user/web/$domain $HOMEDIR/$user/web/$domain/*
+user_exec chmod 551 $HOMEDIR/$user/web/$domain/stats $HOMEDIR/$user/web/$domain/logs
+user_exec chmod 644 $HOMEDIR/$user/web/$domain/public_*html/*
+chown --no-dereference $user:www-data $HOMEDIR/$user/web/$domain/public_*html
 
-# Addding PHP-FPM backend
+# Adding PHP-FPM backend
 if [ ! -z "$WEB_BACKEND" ]; then
     if [ -z "$BACKEND_TEMPLATE" ]; then
         BACKEND_TEMPLATE='default'
@@ -184,7 +214,7 @@ $BIN/v-restart-proxy $restart
 check_result $? "Proxy restart failed" >/dev/null
 
 # Logging
-log_history "added web domain $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Added new web domain (Name: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 11 - 4
bin/v-add-web-domain-alias

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add web domain alias
 # options: USER DOMAIN ALIASES [RESTART]
+# labels: web
+#
+# example: v-add-web-domain-alias admin acme.com www.acme.com yes
 #
 # The call is intended for adding aliases to a domain (it is also called
 # "domain parking"). The function supports wildcards *.domain.tpl.
@@ -18,9 +21,13 @@ aliases=$3
 restart="$4"
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -46,7 +53,7 @@ is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'web' 'DOMAIN' "$domain"
 is_object_unsuspended 'web' 'DOMAIN' "$domain"
 is_domain_new 'web' "$aliases"
-is_package_full 'WEB_ALIASES'
+is_base_domain_owner "$aliases"
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
@@ -56,7 +63,6 @@ check_hestia_demo_mode
 #                       Action                             #
 #----------------------------------------------------------#
 
-# Parsing domain values
 get_domain_values 'web'
 
 # Preparing domain values for the template substitution
@@ -68,6 +74,8 @@ else
 fi
 prepare_web_domain_values
 
+is_package_full 'WEB_ALIASES'
+
 # Rebuilding vhost
 del_web_config "$WEB_SYSTEM" "$TPL.tpl"
 add_web_config "$WEB_SYSTEM" "$TPL.tpl"
@@ -103,8 +111,7 @@ check_result $? "Web restart failed" >/dev/null
 $BIN/v-restart-proxy $restart
 check_result $? "Proxy restart failed" >/dev/null
 
-
-log_history "added $aliases for $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Added new web domain alias (Alias: $aliases, Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 72 - 0
bin/v-add-web-domain-allow-users

@@ -0,0 +1,72 @@
+#!/bin/bash
+# info: Allow other users create subdomains
+# options: USER DOMAIN
+# labels: web hestia
+#
+# example: v-add-web-domain-allow-users admin admin.com
+#
+# Bypass the rule check for Enforce subdomain ownership for a specific domain. 
+# Enforce subdomain ownership setting in /edit/server/ set to no will always overwrite this behaviour
+# eg: admin adds admin.com
+# user can create user.admin.com
+
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+domain_idn=$2
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
+source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
+source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+# Additional argument formatting
+format_domain
+
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DOMAIN'
+is_format_valid 'user' 'domain'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'web' 'DOMAIN' "$domain"
+is_object_unsuspended 'web' 'DOMAIN' "$domain"
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Load domain data
+parse_object_kv_list $(grep "DOMAIN='$domain'" $USER_DATA/web.conf)
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+if [ -z "$ALLOW_USERS" ]; then
+    add_object_key "web" 'DOMAIN' "$domain" 'ALLOW_USERS' 'TIME'
+fi
+
+# Adding new alias
+update_object_value 'web' 'DOMAIN' "$domain" '$ALLOW_USERS' "yes"
+
+$BIN/v-log-action "$user" "Warning" "Web" "Subdomain ownership enforcement disabled (Domain: $domain)."
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 7 - 6
bin/v-add-web-domain-backend

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add web domain backend
 # options: USER DOMAIN [TEMPLATE] [RESTART]
+# labels: web
+#
+# example: v-add-web-domain-backend admin exmaple.com default yes
 #
 # The call is used for adding web backend configuration.
 
@@ -16,8 +19,11 @@ template=${3-default}
 restart=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -43,11 +49,6 @@ check_hestia_demo_mode
 prepare_web_backend
 get_domain_values 'web'
 
-# Checking backend configuration
-#if [ -e "$pool/$backend_type.conf" ]; then
-#    exit
-#fi
-
 # Allocating backend port
 backend_port=9000
 ports=$(grep -v '^;' $pool/* 2>/dev/null |grep listen |grep -o :[0-9].*)
@@ -87,7 +88,7 @@ $BIN/v-restart-web-backend $restart
 check_result $? "Web backend restart failed" >/dev/null
 
 # Logging
-log_history "added $WEB_BACKEND backend configuration for $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Web domain configuration applied (Domain: $domain, Backend: $WEB_BACKEND)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 1
bin/v-add-web-domain-ftp

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add ftp account for web domain.
 # options: USER DOMAIN FTP_USER FTP_PASSWORD [FTP_PATH]
+# labels: web
+#
+# example: v-add-web-domain-ftp alice wonderland.com alice_ftp p4$$vvOrD
 #
 # The function creates additional ftp account for web domain.
 
@@ -18,8 +21,11 @@ password=$4; HIDE=4
 ftp_path=$5
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -130,7 +136,7 @@ update_object_value 'web' 'DOMAIN' "$domain" '$FTP_MD5' "$ftp_md5"
 update_object_value 'web' 'DOMAIN' "$domain" '$FTP_PATH' "$ftp_path"
 
 # Logging
-log_history "added ftp account ${1}_${3}@$domain"
+$BIN/v-log-action "$user" "Info" "Web" "Added new FTP account (Name: ${1}_${3}@$domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 9 - 2
bin/v-add-web-domain-httpauth

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add password protection for web domain
 # options: USER DOMAIN AUTH_USER AUTH_PASSWORD [RESTART]
+# labels: web
+#
+# example: v-add-web-domain-httpauth admin acme.com user02 super_pass
 #
 # The call is used for securing web domain with http auth
 
@@ -17,8 +20,11 @@ password=$4; HIDE=4
 restart=${5-yes}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Defining htpasswd file
@@ -28,7 +34,8 @@ shtaccess="$htaccess"
 shtpasswd="$htpasswd"
 docroot="$HOMEDIR/$user/web/$domain/public_html"
 
-
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 #----------------------------------------------------------#
 #                    Verifications                         #
 #----------------------------------------------------------#
@@ -109,7 +116,7 @@ update_object_value 'web' 'DOMAIN' "$domain" '$AUTH_USER' "$auth_user"
 update_object_value 'web' 'DOMAIN' "$domain" '$AUTH_HASH' "$auth_hash"
 
 # Logging
-log_history "added http auth user $httpauth_user on $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Password protection enabled (Domain: $domain, Username: $httpauth_user)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 1
bin/v-add-web-domain-proxy

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add webdomain proxy support
 # options: USER DOMAIN [TEMPLATE] [EXTENTIONS] [RESTART]
+# labels: web
+#
+# example: v-add-web-domain-proxy admin example.com
 #
 # The function enables proxy support for a domain. This can significantly
 # improve website speed.
@@ -20,9 +23,13 @@ extentions=${4-$default_extentions}
 restart="$5"
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -78,7 +85,7 @@ update_object_value 'web' 'DOMAIN' "$domain" '$PROXY_EXT' "$extentions"
 $BIN/v-restart-proxy $restart
 check_result $? "Proxy restart failed" >/dev/null
 
-log_history "enabled proxy support for $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Proxy enabled (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 121 - 0
bin/v-add-web-domain-redirect

@@ -0,0 +1,121 @@
+#!/bin/bash
+# info: Adding force redirect to domain
+# options: USER DOMAIN REDIRECT HTTPCODE [RESTART]
+# labels: hestia web
+#
+# example: v-add-web-domain-redirect user domain.tld domain.tld 
+# example: v-add-web-domain-redirect user domain.tld www.domain.tld 
+# example: v-add-web-domain-redirect user domain.tld shop.domain.tld  
+# example: v-add-web-domain-redirect user domain.tld different-domain.com
+# example: v-add-web-domain-redirect user domain.tld shop.different-domain.com
+# example: v-add-web-domain-redirect user domain.tld different-domain.com 302
+#
+# Function creates a forced redirect to a domain 
+
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+redirect=$(echo $3 | idn);
+code=${4-301}
+restart=${5-no}
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '3' "$#" 'USER DOMAIN REDIRECT [HTTP-CODE] [RESTART]'
+is_format_valid 'user' 'domain'
+is_number_format_valid "$code" "code"
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'web' 'DOMAIN' "$domain"
+is_object_unsuspended 'web' 'DOMAIN' "$domain"
+
+
+scheme=0
+if [[ "$3" =~ http://|https:// ]]; then
+    scheme=1
+    regex='(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'
+    if ! [[ "$3" =~ $regex ]]; then
+        echo "Invalid redirect"
+        exit 2;
+    fi
+else
+    regex='[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'
+    if ! [[ "$3" =~ $regex ]]; then
+        echo "Invalid redirect"
+        exit 2;
+    fi
+fi
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Check if proxy is active
+if [ "$WEB_SYSTEM" = 'nginx' ] || [ "$PROXY_SYSTEM" = 'nginx' ]; then
+    conf="$HOMEDIR/$user/conf/web/$domain/nginx.conf_redirect"
+    sconf="$HOMEDIR/$user/conf/web/$domain/nginx.ssl.conf_redirect"
+fi
+# Insert redirect commands
+if [ ! -z "$PROXY_SYSTEM" ] || [ "$WEB_SYSTEM" = 'nginx' ]; then
+    if [ "$scheme" = 1 ]; then
+        echo "   return $code $redirect\$request_uri;" > $conf        
+        if [ ! -e "$sconf" ]; then
+            ln -s "$conf" "$sconf"
+        fi
+    else
+        echo "if (\$host != \"$redirect\") {" > $conf
+        echo "   return $code \$scheme://$redirect\$request_uri;" >> $conf
+        echo "}" >> $conf
+        
+        if [ ! -e "$sconf" ]; then
+            ln -s "$conf" "$sconf"
+        fi
+    fi
+else
+    echo "Non supported please use .htaccess instead" 
+    exit 2;
+fi
+
+#----------------------------------------------------------#
+#                       Hestia                             #
+#----------------------------------------------------------#
+
+if [ -z "$REDIRECT" ]; then
+    add_object_key "web" 'DOMAIN' "$domain" 'REDIRECT' 'U_DISK'
+    add_object_key "web" 'DOMAIN' "$domain" 'REDIRECT_CODE' 'U_DISK'
+fi
+
+update_object_value 'web' 'DOMAIN' "$domain" '$REDIRECT' "$redirect"
+update_object_value 'web' 'DOMAIN' "$domain" '$REDIRECT_CODE' "$code"
+
+if [ "$restart" = "yes" ]; then
+    # Restarting web server
+    $BIN/v-restart-web $restart
+    check_result $? "Web restart failed" >/dev/null
+    
+    $BIN/v-restart-proxy $restart
+    check_result $? "Proxy restart failed" >/dev/null
+fi
+
+# Logging
+$BIN/v-log-action "$user" "Info" "Web" "Domain redirection enabled (Domain: $domain, Redirect to: $redirect)."
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 14 - 6
bin/v-add-web-domain-ssl

@@ -1,11 +1,14 @@
 #!/bin/bash
 # info: adding ssl for domain
 # options: USER DOMAIN SSL_DIR [SSL_HOME] [RESTART]
+# labels: web
+#
+# example: v-add-web-domain-ssl admin example.com /home/admin/conf/example.com/web
 #
 # The function turns on SSL support for a domain. Parameter ssl_dir is a path
 # to directory where 2 or 3 ssl files can be found. Certificate file 
-# domain.tld.crt and its key domain.tld.key  are mandatory. Certificate
-# authority domain.tld.ca file is optional. If home directory  parameter
+# domain.tld.crt and its key domain.tld.key are mandatory. Certificate
+# authority domain.tld.ca file is optional. If home directory parameter
 # (ssl_home) is not set, https domain uses public_shtml as separate
 # documentroot directory.
 
@@ -36,9 +39,13 @@ domain=$domain
 domain_idn=$(idn -t --quiet -a "$domain")
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
 source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -93,6 +100,10 @@ if [ -e "$USER_DATA/ssl/$domain.ca" ]; then
     cp -f $USER_DATA/ssl/$domain.ca $HOMEDIR/$user/conf/web/$domain/ssl/$domain.ca
 fi
 
+if [ "$SSL_FORCE" == "yes" ]; then
+    # Enabling SSL redirection on demand
+    $BIN/v-add-web-domain-ssl-force "$user" "$domain"
+fi
 # Parsing domain values
 get_domain_values 'web'
 local_ip=$(get_real_ip $IP)
@@ -120,9 +131,6 @@ increase_user_value "$user" '$U_WEB_SSL'
 update_object_value 'web' 'DOMAIN' "$domain" '$SSL_HOME' "$SSL_HOME"
 update_object_value 'web' 'DOMAIN' "$domain" '$SSL' "yes"
 
-# Enabling automatic SSL redirection
-$BIN/v-add-web-domain-ssl-force "$user" "$domain"
-
 # Restarting web server
 $BIN/v-restart-web $restart
 check_result $? "Web restart failed" >/dev/null
@@ -142,7 +150,7 @@ if [ ! -z "$UPDATE_SSL_SCRIPT" ]; then
 fi
 
 # Logging
-log_history "enabled ssl support for $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Added certificate and enabled SSL (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 13 - 3
bin/v-add-web-domain-ssl-force

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: Adding force SSL for a domain
 # options: USER DOMAIN
+# labels: hestia web
+#
+# example: v-add-web-domain-ssl-force admin acme.com
 #
 # The function forces SSL for the requested domain.
 
@@ -12,9 +15,12 @@
 # Argument definition
 user=$1
 domain=$2
+quiet=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -67,6 +73,8 @@ else
     echo 'RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]' >> $forcessl
 fi
 
+chown root:$user $forcessl
+chmod 640 $forcessl
 
 #----------------------------------------------------------#
 #                       Hestia                             #
@@ -80,15 +88,17 @@ fi
 update_object_value 'web' 'DOMAIN' "$domain" '$SSL_FORCE' 'yes'
 
 # Restart web server
-$BIN/v-restart-web
+$BIN/v-restart-web $restart
 check_result $? "Web restart failed" > /dev/null
 
 # Restart proxy
-$BIN/v-restart-proxy
+$BIN/v-restart-proxy $restart
 check_result $? "Proxy restart failed" > /dev/null
 
 # Logging
-log_history "enabled automatic HTTP-to-HTTPS redirection for $domain"
+if [ "$quiet" != "yes" ]; then
+    $BIN/v-log-action "$user" "Info" "Web" "Automatic HTTPS redirection enabled (Domain: $domain)."
+fi
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 11 - 3
bin/v-add-web-domain-ssl-hsts

@@ -1,6 +1,7 @@
 #!/bin/bash
 # info: Adding hsts to a domain
 # options: USER DOMAIN
+# labels: hestia
 #
 # The function enables HSTS for the requested domain.
 
@@ -12,9 +13,12 @@
 # Argument definition
 user=$1
 domain=$2
+quiet=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -55,6 +59,8 @@ fi
 
 echo 'add_header Strict-Transport-Security "max-age=15768000;" always;' > $hstsconf
 
+chown root:$user $hstsconf
+chmod 640 $hstsconf
 
 #----------------------------------------------------------#
 #                       Hestia                             #
@@ -68,15 +74,17 @@ fi
 update_object_value 'web' 'DOMAIN' "$domain" '$SSL_HSTS' 'yes'
 
 # Restart web server
-$BIN/v-restart-web
+$BIN/v-restart-web $restart
 check_result $? "Web restart failed" > /dev/null
 
 # Restart proxy
-$BIN/v-restart-proxy
+$BIN/v-restart-proxy $restart
 check_result $? "Proxy restart failed" > /dev/null
 
 # Logging
-log_history "enabled HTTP Strict Transport Security (HSTS) for $domain"
+if [ "$quiet" != "yes" ]; then
+    $BIN/v-log-action "$user" "Info" "Web" "HTTP Strict Transport Security (HSTS) enabled (Domain: $domain)."
+fi
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 59 - 0
bin/v-add-web-domain-ssl-preset

@@ -0,0 +1,59 @@
+#!/bin/bash
+# info: Adding force SSL for a domain
+# options: USER DOMAIN [SSL] 
+# labels: hestia web
+#
+# example: v-add-web-domain-ssl-preset
+#
+# Up on creating an web domain set the SSL Force values due to the delay of LE due to DNS propergation over DNS cluster
+# When LE has been activated it will set the actions
+
+#----------------------------------------------------------#
+#                    Variable&Function                     #
+#----------------------------------------------------------#
+
+# Argument definition
+user=$1
+domain=$2
+ssl=$3
+
+# Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
+source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
+source $HESTIA/conf/hestia.conf
+
+#----------------------------------------------------------#
+#                    Verifications                         #
+#----------------------------------------------------------#
+
+check_args '2' "$#" 'USER DOMAIN [SSL]'
+is_format_valid 'user' 'domain' 'ssl'
+is_object_valid 'user' 'USER' "$user"
+is_object_unsuspended 'user' 'USER' "$user"
+is_object_valid 'web' 'DOMAIN' "$domain"
+is_object_unsuspended 'web' 'DOMAIN' "$domain"
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
+#----------------------------------------------------------#
+#                       Action                             #
+#----------------------------------------------------------#
+
+# Load domain data
+parse_object_kv_list $(grep "DOMAIN='$domain'" $USER_DATA/web.conf)
+
+if [  "$ssl" = "yes" ]; then
+    if [ -z "$SSL_FORCE" ]; then
+    add_object_key "web" 'DOMAIN' "$domain" 'SSL_FORCE' 'SSL_HOME'
+    fi
+
+    # Set forcessl flag to enabled
+    update_object_value 'web' 'DOMAIN' "$domain" '$SSL_FORCE' 'yes'
+fi
+
+# Logging
+log_event "$OK" "$ARGUMENTS"
+
+exit

+ 8 - 2
bin/v-add-web-domain-stats

@@ -1,6 +1,9 @@
 #!/bin/bash
-# info: add log analyzer to generate domain statitics
+# info: add log analyzer to generate domain statistics
 # options: USER DOMAIN TYPE
+# labels: web
+#
+# example: v-add-web-domain-stats admin example.com awstats
 #
 # The call is used for enabling log analyzer system to a domain. For viewing
 # the domain statistics use http://domain.tld/vstats/ link. Access this page
@@ -19,8 +22,11 @@ domain_idn=$2
 type=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -98,7 +104,7 @@ echo "$BIN/v-update-web-domain-stat $user $domain" >> \
 update_object_value 'web' 'DOMAIN' "$domain" '$STATS' "$type"
 
 # Logging
-log_history "enabled web log analyzer for $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Web traffic analyzer enabled (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 # Build stats

+ 9 - 3
bin/v-add-web-domain-stats-user

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add password protection to web domain statistics
 # options: USER DOMAIN STATS_USER STATS_PASSWORD [RESTART]
+# labels: web
+#
+# example: v-add-web-domain-stats-user admin example.com watchdog your_password
 #
 # The call is used for securing the web statistics page.
 
@@ -17,8 +20,11 @@ password=$4; HIDE=4
 restart=$5
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -49,8 +55,8 @@ conf_dir="$HOMEDIR/$user/conf/web"
 
 # Adding htaccess file
 if [ "$WEB_SYSTEM" = 'nginx' ]; then
-    echo "auth_basic \"Web Statistics\";" > $conf_dir/$domain.auth
-    echo "auth_basic_user_file $stats_dir/.htpasswd;" >> $conf_dir/$domain.auth
+    echo "auth_basic \"Web Statistics\";" > $stats_dir/auth.conf
+    echo "auth_basic_user_file $stats_dir/.htpasswd;" >> $stats_dir/auth.conf
 else
     echo "AuthUserFile $stats_dir/.htpasswd" > $stats_dir/.htaccess
     echo "AuthName \"Web Statistics\"" >> $stats_dir/.htaccess
@@ -79,7 +85,7 @@ if [ "$WEB_SYSTEM" = 'nginx' ]; then
 fi
 
 # Logging
-log_history "added password protection for web stats on $domain"
+$BIN/v-log-action "$user" "Info" "Web" "Web traffic analyzer password enabled (Username: $stats_user, Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 17 - 6
bin/v-add-web-php

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: add php fpm version
 # options: VERSION
+# labels: hestia
+#
+# example: v-add-web-php 8.0
 #
 # The function checks and delete a fpm php version if not used by any domain.
 
@@ -13,7 +16,9 @@
 version=$1
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -28,19 +33,20 @@ php_fpm="/etc/init.d/php$version-fpm"
 
 # Verify php version format
 if [[ ! $version =~ ^[0-9]\.[0-9]+ ]]; then
-    echo "The php version format is invalid, it should look like [0-9].[0-9]..."
+    echo "The specified PHP version format is invalid, it should look like [0-9].[0-9]."
+    echo "Example:  7.0, 7.4, 8.0"
     exit
 fi
 
 # Check if php version already exists
 if [ -f "$php_fpm" ] && [ -f "$HESTIA/data/templates/web/php-fpm/PHP-${version/\./_}.tpl" ]; then
-    echo "Version already installed..."
+    echo "ERROR: Specified PHP version is already installed."
     exit
 fi
 
 # Check if php version is supported
 if [ ! -f "$HESTIA_INSTALL_DIR/multiphp/$WEB_SYSTEM/PHP-${version//.}.sh" ]; then
-    echo "Version is currently not supported or does not exist..."
+    echo "ERROR: Specified PHP version is not supported or does not exist."
     exit
 fi
 
@@ -63,6 +69,11 @@ if [[ `echo "$version 7.2" | awk '{print ($1 < $2)}'` == 1 ]]; then
     mph="$mph php$version-mcrypt"
 fi
 
+# Check if version is 8.0 or higher and drop php json.
+if [[ ${version:0:1} == "8" ]]; then
+    mph=$(echo "$mph" | sed -e "s/php$version-json//")
+fi
+
 if ! echo "$DB_SYSTEM" | grep -w 'mysql' >/dev/null; then
     mph=$(echo "$mph" | sed -e "s/php$version-mysql//")
 fi
@@ -77,7 +88,7 @@ apt-get -y -qq -o Dpkg::Options::="--force-confold" install $mph > /dev/null 2>&
 BACK_PID=$!
 
 # Check if package installation is done, print a spinner
-echo "Install PHP-$version, please wait..."
+echo "Installing PHP-$version, please wait..."
 spinner="/-\|"
 spin_i=1
 while kill -0 $BACK_PID > /dev/null 2>&1 ; do
@@ -90,7 +101,7 @@ echo
 
 # Check if installation was sucessfully
 if [ ! -f "$php_fpm" ]; then
-    echo "Installation failed, please run the following command manualy for debuging:"
+    echo "ERROR: Installation failed, please run the following command manually for debugging:"
     echo "apt-get install $mph"
 fi
 
@@ -121,7 +132,7 @@ cp -f $HESTIA_INSTALL_DIR/php-fpm/multiphp.tpl \
 #----------------------------------------------------------#
 
 # Logging
-log_history "installed php $version" '' 'admin'
+$BIN/v-log-action "system" "Info" "System" "Installed PHP $version."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 148 - 10
bin/v-backup-user

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: backup system user with all its objects
 # options: USER NOTIFY
+# labels: 
+#
+# example: v-backup-user admin yes
 #
 # The call is used for backing up user with all its domains and databases.
 
@@ -17,12 +20,122 @@ user=$1
 notify=${2-no}
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
 source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/func/backup.sh
 source $HESTIA/func/backup.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
+# Return Disk Usage
+get_user_disk_usage() {
+    u_usage=0
+    web_exclusions=''
+    mail_exclusions=''
+    db_exclusions=''
+    user_exclusions=''
+
+    # Parsing excludes
+    if [ -e "$USER_DATA/backup-excludes.conf" ]; then
+        web_exclusions=$(grep 'WEB=' $USER_DATA/backup-excludes.conf |\
+            awk -F "WEB='" '{print $2}' | cut -f 1 -d \')
+        mail_exclusions=$(grep 'MAIL=' $USER_DATA/backup-excludes.conf |\
+            awk -F "MAIL='" '{print $2}' | cut -f 1 -d \')
+        db_exclusions=$(grep 'DB=' $USER_DATA/backup-excludes.conf |\
+            awk -F "DB='" '{print $2}' | cut -f 1 -d \')
+        user_exclusions=$(grep 'USER=' $USER_DATA/backup-excludes.conf |\
+            awk -F "USER='" '{print $2}' | cut -f 1 -d \')
+    fi
+
+    if [ -f "$USER_DATA/web.conf" ] && [ "$web_exclusions" != '*' ]; then
+        usage=0
+        domains=$(grep 'DOMAIN=' $USER_DATA/web.conf |\
+            awk -F "DOMAIN='" '{print $2}' | cut -f 1 -d \')
+
+        for domain in $domains; do
+            exclusion=$(echo -e "$web_exclusions" |tr ',' '\n' |grep "^$domain$")
+            if [ -z "$exclusion" ]; then
+                # Defining home directory
+                home_dir="$HOMEDIR/$user/web/$domain/"
+                exlusion=$(echo -e "$web_exclusions" |tr ',' '\n' |grep "^$domain:")
+                fargs=()
+
+                if [ ! -z "$exlusion" ]; then
+                    xdirs="$(echo -e "$exlusion" |tr ':' '\n' |grep -v $domain)"
+                    for xpath in $xdirs; do
+                        fargs+=(--exclude=$xpath)
+                    done
+                fi
+
+                # Checking home directory exist
+                if [ -e "$home_dir" ]; then
+                    disk_usage=$(nice -n 19 du -shm $home_dir ${fargs[@]} | cut -f 1 )
+                    u_usage=$((u_usage + disk_usage))
+                fi
+            fi
+        done
+    fi
+
+    if [ -f "$USER_DATA/mail.conf" ] && [ "$mail_exclusions" != '*' ]; then
+        usage=0
+        domains=$(grep 'DOMAIN=' $USER_DATA/mail.conf |\
+            awk -F "DOMAIN='" '{print $2}' | cut -f 1 -d \')
+
+        for domain in $domains; do
+            check_exl=$(echo "$mail_exclusions" |tr ',' '\n' |grep "^$domain$")
+            if [ -f "$USER_DATA/mail/$domain.conf" ] && [ -z "$check_exl" ]; then
+                accounts=$(grep 'ACCOUNT=' $USER_DATA/mail/$domain.conf |\
+                    awk -F "ACCOUNT='" '{print $2}' | cut -f 1 -d \')
+
+                for account in $accounts; do
+                    home_dir=$HOMEDIR/$user/mail/$domain/$account
+                    exclusion=$(echo "$mail_exclusions" |tr ',' '\n' |grep "$domain:")
+                    exclusion=$(echo "$exclusion" |tr ':' '\n' |grep -E "^$account|\*")
+
+                    if [ -z "$exclusion" ] && [ -e "$home_dir" ]; then
+                        disk_usage=$(nice -n 19 du -shm $home_dir | cut -f 1 )
+                        u_usage=$((u_usage + disk_usage))
+                    fi
+                done
+            fi
+        done
+    fi
+
+    if [ -f "$USER_DATA/db.conf" ] && [ "$db_exclusions" != '*' ]; then
+        usage=0
+        databases=$(grep 'DB=' $USER_DATA/db.conf |\
+            awk -F "DB='" '{print $2}' | cut -f 1 -d \')
+        for database in $databases; do
+            exclusion=$(echo "$db_exclusions" |tr ',' '\n' |grep "^$database$")
+            if [ -z "$exclusion" ]; then
+                # Get database values
+                get_database_values
+
+                # Switching on db type
+                case $DB_SYSTEM in
+                    mysql) get_mysql_disk_usage ;;
+                    pgsql) get_pgsql_disk_usage ;;
+                esac
+                u_usage=$((u_usage + usage))
+            fi
+        done
+    fi
+
+    if [ "$user_exclusions" != '*' ]; then
+        fargs=()
+        for xpath in $(echo "$user_exclusions" |tr ',' '\n'); do
+            fargs+=(--exclude=$xpath)
+        done
+        usage=$(du -shm $HOMEDIR/$user --exclude $HOMEDIR/$user/web --exclude $HOMEDIR/$user/mail --exclude $HOMEDIR/$user/conf ${fargs[@]} |cut -f 1 )
+        u_usage=$((u_usage + usage))
+    fi
+
+    echo ${u_usage}
+}
 
 #----------------------------------------------------------#
 #                    Verifications                         #
@@ -35,6 +148,8 @@ is_object_valid 'user' 'USER' "$user"
 is_object_unsuspended 'user' 'USER' "$user"
 is_backup_enabled
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #
@@ -46,7 +161,14 @@ check_backup_conditions
 if [ -z "$BACKUP" ]; then
     BACKUP=/backup
 fi
-mkdir -p $BACKUP
+
+# Check if backup folder exists and have the correct permission
+if [[ ! -d "$BACKUP" ]]; then 
+    mkdir -p $BACKUP
+fi
+if [ $(stat -c %a $BACKUP) != 755 ]; then
+    chmod 755 $BACKUP
+fi
 
 # Get current time
 start_time=$(date '+%s')
@@ -56,11 +178,12 @@ subj="$user → backup failed"
 email=$(grep CONTACT $HESTIA/data/users/admin/user.conf |cut -f 2 -d \')
 
 # Validate available disk space (take usage * 2, due to the backup handling)
-let u_disk=$(grep "U_DISK=" $HESTIA/data/users/$user/user.conf |cut -f 2 -d \')*2
+let u_disk=$(($(get_user_disk_usage) * 2))
 let v_disk=$(($(stat -f --format="%a*%S" $BACKUP)))/1024/1024
 
 if [ "$u_disk" -gt "$v_disk" ]; then
-    echo "not enough diskspace available to perform the backup." |$SENDMAIL -s "$subj" $email $notify
+    # Always notify on failure
+    echo "not enough diskspace available to perform the backup." | $SENDMAIL -s "$subj" $email "yes"
     check_result $E_LIMIT "not enough diskspace available to perform the backup."
 fi
 
@@ -72,7 +195,7 @@ fi
 tmpdir=$(mktemp -p $BACKUP_TEMP -d)
 
 if [ "$?" -ne 0 ]; then
-    echo "Can't create tmp dir $tmpdir" |$SENDMAIL -s "$subj" $email $notify
+    echo "Can't create tmp dir $tmpdir" |$SENDMAIL -s "$subj" $email "yes"
     check_result $E_NOTEXIST "can't create tmp dir"
 fi
 
@@ -266,7 +389,7 @@ if [ ! -z "$WEB_SYSTEM" ] && [ "$WEB" != '*' ]; then
 
         # Backup files
         if [ "$BACKUP_MODE" = 'zstd' ]; then
-            tar ${fargs[@]} -cpf- * | zstd -$BACKUP_GZIP - > $tmpdir/web/$domain/domain_data.tar.zst
+            tar ${fargs[@]} -cpf- * | pzstd -$BACKUP_GZIP - > $tmpdir/web/$domain/domain_data.tar.zst
         else    
             tar ${fargs[@]} -cpf- * | gzip -$BACKUP_GZIP - > $tmpdir/web/$domain/domain_data.tar.gz
         fi
@@ -372,7 +495,7 @@ if [ ! -z "$MAIL_SYSTEM" ] && [ "$MAIL" != '*' ]; then
         accounts=()
         for account in $(ls); do
             exclusion=$(echo "$MAIL" |tr ',' '\n' |grep "$domain:")
-            exclusion=$(echo "$exclusion" |tr ':' '\n' |grep "^$account$")
+            exclusion=$(echo "$exclusion" |tr ':' '\n' |grep -E "^$account|\*")
 
             # Checking exlusions
             if [ -z "$exclusion" ] && [[ "$MAIL_SYSTEM" =~ exim ]]; then
@@ -385,7 +508,7 @@ if [ ! -z "$MAIL_SYSTEM" ] && [ "$MAIL" != '*' ]; then
         # Compress archive
         if [ ${#accounts[@]} -gt 0 ]; then
             if [ "$BACKUP_MODE" = 'zstd' ]; then
-                tar -cpf- ${accounts[@]}  | zstd -$BACKUP_GZIP - > $tmpdir/mail/$domain/accounts.tar.zst
+                tar -cpf- ${accounts[@]}  | pzstd -$BACKUP_GZIP - > $tmpdir/mail/$domain/accounts.tar.zst
             else    
                 tar -cpf- ${accounts[@]} | gzip -$BACKUP_GZIP - > $tmpdir/mail/$domain/accounts.tar.gz
             fi        
@@ -465,7 +588,7 @@ if [ ! -z "$DB_SYSTEM" ] && [ "$DB" != '*' ]; then
 
             # Compress dump
             if [ "$BACKUP_MODE" = 'zstd' ]; then
-                zstd -$BACKUP_GZIP $dump
+                pzstd -$BACKUP_GZIP $dump
                 rm $dump;
             else    
                 gzip -$BACKUP_GZIP $dump
@@ -546,7 +669,7 @@ if [ "$USER" != '*' ]; then
 
             # Backup files and dirs
             if [ "$BACKUP_MODE" = 'zstd' ]; then
-                tar --anchored -cpf- ${fargs[@]} $udir | zstd -$BACKUP_GZIP - > $tmpdir/user_dir/$udir.tar.zst
+                tar --anchored -cpf- ${fargs[@]} $udir | pzstd -$BACKUP_GZIP - > $tmpdir/user_dir/$udir.tar.zst
             else    
                 tar --anchored -cpf- ${fargs[@]} $udir | gzip -$BACKUP_GZIP - > $tmpdir/user_dir/$udir.tar.gz
             fi 
@@ -582,6 +705,7 @@ backup_new_date=$(date +"%Y-%m-%d_%H-%M-%S")
 
 echo -e "\n-- SUMMARY --" |tee -a $BACKUP/$user.log
 
+errorcode="0"
 # Switching on backup system types
 for backup_type in $(echo -e "${BACKUP_SYSTEM//,/\\n}"); do
     case $backup_type in
@@ -589,12 +713,24 @@ for backup_type in $(echo -e "${BACKUP_SYSTEM//,/\\n}"); do
         ftp)   ftp_backup ;;
         sftp)  sftp_backup ;;
         google) google_backup ;;
+        b2) b2_backup ;;
     esac
 done
 
 # Removing tmpdir
 rm -rf $tmpdir
+if [[ "$errorcode" != "0" ]]; then
+    if [[ "$BACKUP_SYSTEM"  =~ "local" ]]; then 
+        echo -e "$(date "+%F %T") *** Local backup was successfully executed. Remote backup failed ***" |\
+        tee -a $BACKUP/$user.log
+        BACKUP_SYSTEM="local"
+    else
+        echo -e "$(date "+%F %T") *** Remote backup failed ***" |\
+        tee -a $BACKUP/$user.log
 
+        exit $error_code;
+    fi
+fi
 # Calculation run time
 run_time=$((end_time - start_time))
 run_time=$((run_time / 60))
@@ -641,10 +777,10 @@ sed -i "/v-backup-user $user /d" $HESTIA/data/queue/backup.pipe
 
 U_BACKUPS=$(grep BACKUP $USER_DATA/backup.conf |wc -l)
 update_user_value "$user" '$U_BACKUPS' "$U_BACKUPS"
+cd $BACKUP
 
 # Send notification
 if [ -e "$BACKUP/$user.log" ] && [ "$notify" = "yes" ]; then
-    cd $BACKUP
     subj="$user → backup has been completed"
     email=$(get_user_value '$CONTACT')
     cat $BACKUP/$user.log |$SENDMAIL -s "$subj" $email $notify
@@ -653,6 +789,8 @@ if [ -e "$BACKUP/$user.log" ] && [ "$notify" = "yes" ]; then
 fi
 
 # Logging
+$BIN/v-log-action "$user" "Info" "Backup" "Backup created (Archive: $backup_new_date.tar)."
+$BIN/v-log-action "system" "Info" "Backup" "Backup created (User: $user, Archive: $backup_new_date.tar)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 1
bin/v-backup-users

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: backup all users
 # options: NONE
+# labels: 
+#
+# example: v-backup-users
 #
 # The function backups all system users.
 
@@ -14,10 +17,13 @@
 source /etc/profile
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
-
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#

+ 6 - 1
bin/v-change-cron-job

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change cron job
 # options: USER JOB MIN HOUR DAY MONTH WDAY COMMAND
+# labels: 
+#
+# example: v-change-cron-job admin 7 * * * * * * /usr/bin/uptime
 #
 # The function is used for changing existing job. It fully replace job
 # parameters with new one but with same id.
@@ -21,7 +24,9 @@ wday=$7
 command=$8
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -77,7 +82,7 @@ $BIN/v-restart-cron
 check_result $? "Cron restart failed" >/dev/null
 
 # Logging
-log_history "changed cron job $job"
+$BIN/v-log-action "$user" "Info" "Cron Jobs" "Cron job updated (Job: $job, Command: $command)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 0
bin/v-change-database-host-password

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change database server password
 # options: TYPE HOST USER PASSWORD
+# labels: 
+#
+# example: v-change-database-host-password mysql localhost wp_user pA$$w@rD
 #
 # The function changes database server password.
 
@@ -16,8 +19,11 @@ dbuser=$3
 password=$4; HIDE=4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
 source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -66,6 +72,7 @@ update_object_value "../../conf/$type" 'HOST' "$host" '$PASSWORD' "$dbpass"
 #----------------------------------------------------------#
 
 # Logging
+$BIN/v-log-action "system" "Warning" "Database" "Password changed for remote database host (Host: $host)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 0
bin/v-change-database-owner

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change database owner
 # options: DATABASE USER
+# labels: 
+#
+# example: v-change-database-owner mydb alice
 #
 # The function for changing database owner.
 
@@ -15,9 +18,13 @@ user=$2
 
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
 source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
 source $HESTIA/func/rebuild.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 

+ 8 - 2
bin/v-change-database-password

@@ -1,8 +1,11 @@
 #!/bin/bash
 # info: change database password
 # options: USER DATABASE DBPASS
+# labels: 
 #
-# The function for changing database user  password to a database. It uses the
+# example: v-change-database-password admin wp_db neW_pAssWorD
+#
+# The function for changing database user password to a database. It uses the
 # full name of database as argument.
 
 
@@ -16,8 +19,11 @@ database=$2
 password=$3; HIDE=3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
 source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -59,7 +65,7 @@ esac
 update_object_value 'db' 'DB' "$database" '$MD5' "$md5"
 
 # Logging
-log_history "changed $database database password"
+$BIN/v-log-action "$user" "Info" "Database" "Database password changed (Database: $database)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 1
bin/v-change-database-user

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change database username
 # options: USER DATABASE DBUSER [DBPASS]
+# labels: 
+#
+# example: v-change-database-user admin my_db joe_user
 #
 # The function for changing database user. It uses the
 
@@ -16,9 +19,13 @@ dbuser="$user"_"$3"
 password=$4; HIDE=4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/db.sh
 source $HESTIA/func/db.sh
+# shellcheck source=/usr/local/hestia/func/rebuild.sh
 source $HESTIA/func/rebuild.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -93,7 +100,7 @@ fi
 #----------------------------------------------------------#
 
 # Logging
-log_history "changed $database database user to $dbuser"
+$BIN/v-log-action "$user" "Info" "Database" "Database user changed (Database: $database, User: $dbuser)"
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 6 - 1
bin/v-change-dns-domain-exp

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change dns domain expiration date
 # options: USER DOMAIN EXP
+# labels: dns
+#
+# example: v-change-dns-domain-exp admin domain.pp.ua 2020-11-20
 #
 # The function of changing the term of expiration domain's registration. The
 # serial number will be refreshed automatically during update.
@@ -17,7 +20,9 @@ domain_idn=$2
 exp=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -65,7 +70,7 @@ fi
 #----------------------------------------------------------#
 
 # Logging
-log_history "changed whois expiration date for $domain"
+$BIN/v-log-action "$user" "Info" "DNS" "Updated DNS SOA expiration date (Domain: $domain, Value: $exp)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 9 - 3
bin/v-change-dns-domain-ip

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change dns domain ip address
-# options: USER DOMAIN IP
+# options: USER DOMAIN IP [RESTART]
+# labels: dns
+#
+# example: v-change-dns-domain-ip admin domain.com 123.212.111.222
 #
 # The function for changing the main ip of DNS zone.
 
@@ -17,8 +20,11 @@ ip=$3
 restart=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -31,7 +37,7 @@ format_domain_idn
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '3' "$#" 'USER DOMAIN IP'
+check_args '3' "$#" 'USER DOMAIN IP [RESTART]'
 is_format_valid 'user' 'domain' 'ip'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
@@ -83,7 +89,7 @@ $BIN/v-restart-dns $restart
 check_result $? "DNS restart failed" >/dev/null
 
 # Logging
-log_history "changed dns ip for $domain to $ip"
+$BIN/v-log-action "$user" "Info" "DNS" "IP address for DNS domain changed (IP: $ip, Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 9 - 3
bin/v-change-dns-domain-soa

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change dns domain soa record
-# options: USER DOMAIN SOA
+# options: USER DOMAIN SOA [RESTART]
+# labels: dns
+#
+# example: v-change-dns-domain-soa admin acme.com d.ns.domain.tld
 #
 # The function for changing SOA record. This type of records can not be
 # modified by v-change-dns-record call.
@@ -18,8 +21,11 @@ soa=$(echo $3 | sed -e 's/\.*$//g' -e 's/^\.*//g')
 restart=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -32,7 +38,7 @@ format_domain_idn
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '3' "$#" 'USER DOMAIN SOA'
+check_args '3' "$#" 'USER DOMAIN SOA [RESTART]'
 is_format_valid 'user' 'domain' 'soa'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
@@ -77,7 +83,7 @@ $BIN/v-restart-dns $restart
 check_result $? "DNS restart failed" >/dev/null
 
 # Logging
-log_history "changed soa record for $domain to $soa"
+$BIN/v-log-action "$user" "Info" "DNS" "SOA record for DNS domain changed (SOA: $soa, Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 2
bin/v-change-dns-domain-tpl

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change dns domain template
 # options: USER DOMAIN TEMPLATE [RESTART]
+# labels: dns
+#
+# example: v-change-dns-domain-tpl admin example.com child-ns yes
 #
 # The function for changing the template of records. By updating old records
 # will be removed and new records will be generated in accordance with
@@ -19,8 +22,11 @@ template=$3
 restart=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -121,7 +127,7 @@ if [ "$template" = "office365" ]; then
     if [ "$?" -eq 0 ]; then
         record='@'
         formatted_domain=$(echo "$domain" | sed 's/\./-/g')
-        $BIN/v-add-dns-record $user $domain $record MX "${formatted_domain}.mail.protection.outlook.com." '0'
+        $BIN/v-add-dns-record $user $domain $record MX "${formatted_domain}.mail.protection.outlook.com." '0' '' $restart
     fi
 fi
 
@@ -160,7 +166,7 @@ $BIN/v-restart-dns $restart
 check_result $? "DNS restart failed" >/dev/null
 
 # Logging
-log_history "changed dns template for $domain to $template" '' 'admin'
+$BIN/v-log-action "system" "Info" "DNS" "Template for DNS domain changed (Template: $template, Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 9 - 3
bin/v-change-dns-domain-ttl

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change dns domain ttl
-# options: USER DOMAIN TTL
+# options: USER DOMAIN TTL [RESTART]
+# labels: dns
+#
+# example: v-change-dns-domain-ttl alice example.com 14400
 #
 # The function for changing the time to live TTL parameter for all records.
 
@@ -17,8 +20,11 @@ ttl=$3
 restart=$4
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -31,7 +37,7 @@ format_domain_idn
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '3' "$#" 'USER DOMAIN TTL'
+check_args '3' "$#" 'USER DOMAIN TTL [RESTART]'
 is_format_valid 'user' 'domain' 'ttl'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
@@ -76,7 +82,7 @@ $BIN/v-restart-dns $restart
 check_result $? "DNS restart failed" >/dev/null
 
 # Logging
-log_history "changed TTL for $domain to $ttl"
+$BIN/v-log-action "$user" "Info" "DNS" "TTL for DNS domain changed (TTL: $ttl, Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 2
bin/v-change-dns-record

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change dns domain record
-# options: USER DOMAIN ID VALUE [PRIORITY] [RESTART] [TTL]
+# options: USER DOMAIN ID RECORD TYPE VALUE [PRIORITY] [RESTART] [TTL]
+# labels: dns
+#
+# example: v-change-dns-record admin domain.ua 42 192.18.22.43
 #
 # The function for changing DNS record.
 
@@ -22,8 +25,11 @@ restart=$8
 ttl=$9
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -122,7 +128,7 @@ $BIN/v-restart-dns $restart
 check_result $? "DNS restart failed" >/dev/null
 
 # Logging
-log_history "changed dns record on $domain to $dvalue"
+$BIN/v-log-action "$user" "Info" "DNS" "DNS record value changed (Type: $type, Record: $record, Value: $dvalue, Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 8 - 1
bin/v-change-dns-record-id

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change dns domain record id
 # options: USER DOMAIN ID NEWID [RESTART]
+# labels: dns
+#
+# example: v-change-dns-record-id admin acme.com 24 42 yes
 #
 # The function for changing internal record id.
 
@@ -18,8 +21,11 @@ newid=$4
 restart=$5
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/domain.sh
 source $HESTIA/func/domain.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Additional argument formatting
@@ -42,6 +48,8 @@ is_object_unsuspended 'dns' 'DOMAIN' "$domain"
 is_object_valid "dns/$domain" 'ID' "$id"
 is_object_new "dns/$domain" 'ID' "$newid"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
 
 #----------------------------------------------------------#
 #                       Action                             #
@@ -79,7 +87,6 @@ $BIN/v-restart-dns $restart
 check_result $? "DNS restart failed" >/dev/null
 
 # Logging
-log_history "changed dns record id on $domain"
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 17 - 5
bin/v-change-domain-owner

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change domain owner
 # options: DOMAIN USER
+# labels: 
+#
+# example: v-change-domain-owner www.example.com bob
 #
 # The function of changing domain ownership.
 
@@ -14,8 +17,11 @@ domain=$1
 user=$2
 
 # Includes
-source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/func/ip.sh
+source $HESTIA/func/ip.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 
@@ -94,6 +100,9 @@ if [ ! -z "$web_data" ]; then
     $BIN/v-unsuspend-web-domain $user $domain no >> /dev/null 2>&1
     $BIN/v-rebuild-web-domains $owner no
     $BIN/v-rebuild-web-domains $user
+
+    # Cleanup old config
+    rm -rf $HOMEDIR/$owner/conf/web/$domain/
 fi
 
 # DNS domain
@@ -121,9 +130,12 @@ if [ ! -z "$dns_data" ]; then
     $BIN/v-rebuild-dns-domains $owner no
     $BIN/v-rebuild-dns-domains $user
 
+    # Cleanup old config
+    rm -f $HOMEDIR/$owner/conf/dns/$domain.db
+
     # Resync dns cluster
     if [ ! -z "$DNS_CLUSTER" ]; then
-        v-sync-dns-cluster
+        $BIN/v-sync-dns-cluster
     fi
 fi
 
@@ -255,9 +267,9 @@ fi
 #----------------------------------------------------------#
 
 # Logging
-log_history "moved domain $domain from $owner to $user" '' "admin"
-log_history "$domain was added to your account" '' "$user"
-log_history "$domain was removed from your account" '' "$owner"
+$BIN/v-log-action "system" "Info" "System" "Domain moved between users (Domain: $domain, Old user: $owner, New User: $user)."
+$BIN/v-log-action "$user" "Info" "System" "New domain added to account (Domain: $domain)."
+$BIN/v-log-action "$owner" "Info" "System" "Domain removed from account (Domain: $domain)."
 log_event "$OK" "$ARGUMENTS"
 
 exit

+ 7 - 2
bin/v-change-firewall-rule

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change firewall rule
 # options: RULE ACTION IP PORT [PROTOCOL] [COMMENT]
+# labels: 
+#
+# example: v-change-firewall-rule 3 ACCEPT 5.188.123.17 443
 #
 # The function is used for changing existing firewall rule.
 # It fully replace rule with new one but keeps same id.
@@ -23,7 +26,9 @@ protocol=$(echo $protocol|tr '[:lower:]' '[:upper:]')
 comment=$6
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
+# shellcheck source=/usr/local/hestia/conf/hestia.conf
 source $HESTIA/conf/hestia.conf
 
 # Sort function
@@ -39,7 +44,7 @@ sort_fw_rules() {
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '5' "$#" 'RULE ACTION IP  PORT [PROTOCOL] [COMMENT]'
+check_args '4' "$#" 'RULE ACTION IP PORT [PROTOCOL] [COMMENT]'
 is_format_valid 'rule' 'action' 'protocol' 'port_ext'
 if [ ! -z "$comment" ]; then
     is_format_valid 'comment'
@@ -91,6 +96,6 @@ $BIN/v-update-firewall
 #----------------------------------------------------------#
 
 # Logging
+$BIN/v-log-action "system" "Info" "Firewall" "Firewall rule changed (Rule: $rule, Action: $action, Protocol: $protocol, Port: $port_ext)."
 log_event "$OK" "$ARGUMENTS"
-
 exit

+ 9 - 0
bin/v-change-fs-file-permission

@@ -1,6 +1,9 @@
 #!/bin/bash
 # info: change file permission
 # options: USER FILE PERMISSIONS
+# labels: 
+#
+# example: v-change-fs-file-permission admin readme.txt 0777
 #
 # The function changes file access permissions on the file system
 
@@ -9,6 +12,7 @@ src_file=$2
 permissions=$3
 
 # Includes
+# shellcheck source=/usr/local/hestia/func/main.sh
 source $HESTIA/func/main.sh
 
 #----------------------------------------------------------#
@@ -19,6 +23,9 @@ check_args '3' "$#" 'USER FILE PERMISSIONS'
 is_format_valid 'user'
 is_object_valid 'user' 'USER' "$user"
 
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
 # Checking user homedir
 homedir=$(grep "^$user:" /etc/passwd | cut -f 6 -d :)
 if [ -z $homedir ]; then
@@ -46,5 +53,7 @@ if [ $? -ne 0 ]; then
     exit 3
 fi
 
+$BIN/v-log-action "system" "Info" "System" "File system permissions changed (User: $user, File: $src_file, Permissions: $permissions)."
+
 # Exiting
 exit

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