Compare commits

...

163 Commits

Author SHA1 Message Date
tom mortensen
4190c6c822 Merge pull request #1693 from zackspear/refactor/6.12-trial-messaging-replace-pro-with-unleashed
[6.12] refactor: web component translations trial messaging
2024-04-02 08:55:33 -07:00
Zack Spear
2901a1949f chore(wc): remove unraid.min.js 2024-04-02 11:01:37 +09:00
Zack Spear
dfde9b68c0 refactor: web component translations trial messaging 2024-04-02 09:46:47 +09:00
Tom Mortensen
98b52dc95f properly display zfs profile when device is missing 2024-04-01 12:02:59 -07:00
tom mortensen
730b8ef91c Merge pull request #1688 from zackspear/refactor/6.12-trial-messaging-replace-pro-with-unleashed
[6.12] refactor(wc): trial messaging replace pro with unleashed
2024-04-01 09:43:54 -07:00
tom mortensen
e2d7b6f15c Merge pull request #1689 from SimonFair/SysDriversLanguageFixbackport6.12
Fix issue with SystemDrivers for 6.12.
2024-04-01 09:40:17 -07:00
SimonFair
29e02bfc07 Fix issue with SystemDrivers. 2024-04-01 17:17:06 +01:00
Zack Spear
50567f450c refactor(wc): trial messaging replace pro with unleashed 2024-04-01 22:00:18 +09:00
tom mortensen
cd52d6a7df Merge pull request #1682 from zackspear/feat/6.12-config-error-messaging
[6.12] feat(upc): server config enum messaging
2024-03-26 15:14:50 -07:00
Zack Spear
29e2084181 refactor: config error messages 2024-03-27 01:23:08 +09:00
Zack Spear
cde846757b feat(upc): server config enum messaging 2024-03-26 19:47:01 +09:00
Tom Mortensen
69641222bf support 'inelgible' configValid state 2024-03-25 13:41:16 -07:00
tom mortensen
16e058c62d Merge pull request #1676 from zackspear/fix/6-12-regDevs-usage-for-more-flexibility
[6.12] fix: regDevs usage for more flexibility
2024-03-23 00:11:08 -07:00
tom mortensen
109eb31b17 Merge pull request #1679 from unraid/backport-php-warning-fixes
Backport: Fixes for PHP Warnings
2024-03-23 00:10:24 -07:00
ljm42
0b850b058b Backport: Fixes for PHP Warnings 2024-03-21 12:05:46 -07:00
Zack Spear
bc5c8a8bc5 fix: regDevs usage 2024-03-21 21:01:28 +09:00
Tom Mortensen
3a53d311d2 kernel change requires bond interface change 2024-03-15 14:37:42 -07:00
tom mortensen
900afa2105 Merge pull request #1674 from zackspear/6.12
[6.12] refactor(upc): add upgrade button for key state
2024-03-15 14:34:30 -07:00
tom mortensen
fcdf88f997 Merge pull request #1672 from unraid/backport-fix-notifications
Backport Fix Docker notifications
2024-03-15 14:33:54 -07:00
tom mortensen
83cad5852c Merge pull request #1670 from SimonFair/SysDriversLanguageFixbackport6.12
FIx Language issue backport
2024-03-15 14:33:02 -07:00
tom mortensen
cbfb8a3a90 Merge pull request #1666 from unraid/backport-remove-legacy-certs
Backport: remove support for legacy unraid.net certs
2024-03-15 14:16:35 -07:00
tom mortensen
24535c7272 Merge pull request #1664 from unraid/backport-disable-updatedns2
Backport Disable UpdateDNS
2024-03-15 14:16:02 -07:00
Zack Spear
3226f4a1c7 refactor(upc): add upgrade button for key state 2024-03-15 13:14:17 -07:00
ljm42
ee3d28a978 Backport Fix Docker notifications
Backport #1671
2024-03-14 14:25:16 -07:00
SimonFair
262aea7312 FIx Language issue backport 2024-03-14 19:40:57 +00:00
ljm42
ed19f86e7d Backport: remove support for legacy unraid.net certs 2024-03-13 15:39:29 -07:00
ljm42
d238203acc Disable UpdateDNS
Also backport my_logger() function to simplify backporting
2024-03-13 14:11:05 -07:00
tom mortensen
2ff0d408a8 Merge pull request #1662 from zackspear/6.12
refactor(upc): remove UpdateDNS requests on key install
2024-03-13 09:44:40 -07:00
tom mortensen
8ad4d879f3 Merge pull request #1661 from unraid/backport-disable-updatedns
Backport Disable UpdateDNS
2024-03-13 09:44:19 -07:00
tom mortensen
dcfc6f9a1d Merge pull request #1655 from Squidly271/patch-30
Backport Fix PHP8 Warnings in Notification Archive
2024-03-13 09:42:17 -07:00
tom mortensen
e549b4a928 Merge pull request #1652 from unraid/backport-feat-add-phplog-to-diags
Backport: Diagnostics: add phplog
2024-03-13 09:40:46 -07:00
tom mortensen
18044d98cc Merge pull request #1649 from ich777/backport_6.12_mgmtaccess_ipv6_fix
Backport Update ManagementAccess.page
2024-03-13 09:40:21 -07:00
Zack Spear
5eaaf2c220 refactor(upc): remove UpdateDNS requests on key install 2024-03-12 15:11:53 -07:00
ljm42
c1b5a6ef7b Backport Disable UpdateDNS 2024-03-12 14:40:50 -07:00
Squidly271
4ffc04cd72 Update notify_poller 2024-03-09 12:54:43 -05:00
Squidly271
9ad869e134 Update NotificationsArchive.php 2024-03-09 11:32:22 -05:00
ljm42
e02713eeac Backport: Diagnostics: add phplog 2024-03-07 13:05:32 -07:00
60ab17d7ea Update ManagementAccess.page
- backport #1648 (Fix IPv6 not displaying correctly on Management Access page if using default ports)
2024-03-06 17:52:08 +01:00
tom mortensen
f80813a73d Merge pull request #1646 from Squidly271/patch-26
Backport Fix Docker Update Issues
2024-03-04 15:01:47 -08:00
tom mortensen
235011d547 Merge pull request #1643 from unraid/backport-fix-getDockerJSON
Backport: Fix getDockerJSON
2024-03-04 15:00:25 -08:00
Squidly271
9789659f83 Backport Fix Docker Update Issues 2024-03-03 12:12:26 -05:00
ljm42
50c47005ba Backport: Fix getDockerJSON
Backport #1640
2024-03-01 13:03:02 -07:00
tom mortensen
d0c40d5269 Merge pull request #1641 from zackspear/6.12
[6.12] fix: state special chars for html attrs & updates button conditionals + date formatting
2024-02-29 16:35:34 -08:00
Zack Spear
aad6cf6408 fix: update os check modal button conditionals and date formatting 2024-02-29 15:28:21 -08:00
Zack Spear
ae19e2aa16 refactor: upc special chars handling 2024-02-27 16:33:10 -08:00
Zack Spear
96059fc4b5 fix: unraidcheck date format 2024-02-27 16:29:52 -08:00
Zack Spear
a3be910f24 fix: state php special chars for html attributes 2024-02-27 16:29:35 -08:00
tom mortensen
ad002faf36 Merge pull request #1636 from zackspear/fix/6-12-description-double-quotes
fix: state php breaking with double quotes in server description [6.12]
2024-02-23 16:05:01 -08:00
Zack Spear
f5257dd134 fix: state php breaking with double quotes in server description 2024-02-21 12:33:37 -08:00
tom mortensen
a479a1bd86 Merge pull request #1630 from Squidly271/patch-22
Backport Docker Ignore Empty Paths
2024-02-21 09:00:13 -08:00
tom mortensen
1c07f6fdc7 Merge pull request #1627 from zackspear/fix/6-12-state-cfg-usage
fix: state connect values without connect installed [6.12]
2024-02-21 08:58:02 -08:00
Squidly271
335d9eb225 Update Helpers.php 2024-02-17 07:15:32 -05:00
Zack Spear
4d50eaa3ab fix: state connect values without connect installed 2024-02-16 16:51:47 -08:00
tom mortensen
8e3913146b Merge pull request #1625 from zackspear/fix/os-plg-update
fix: os updates rc to stable [6.12]
2024-02-15 17:06:41 -08:00
Zack Spear
5bc9be6036 fix: os updates rc to stable 2024-02-15 14:16:13 -08:00
tom mortensen
3af48b4393 Merge pull request #1624 from unraid/backport-managementaccess
Backport to 6.12 - Management access: fix incorrect ip address display
2024-02-15 07:50:27 -08:00
ljm42
98127c95f8 Backport to 6.12 - Management access: fix incorrect ip address display 2024-02-14 13:56:29 -07:00
tom mortensen
aa012f00f6 Merge pull request #1622 from zackspear/fix/6.12-upc-dropdown-reboot-link-text
fix: dropdown reboot link text [6.12]
2024-02-14 08:41:26 -08:00
Zack Spear
a5db8d917a fix: dropdown reboot link 2024-02-13 17:59:00 -08:00
Tom Mortensen
2bd92658ab give dhcpcd 45 sec up from 30 sec to obtain LAN IP address 2024-02-12 12:07:53 -08:00
tom mortensen
ce56b9008c Merge pull request #1619 from Squidly271/patch-20
Backport PHP8 Fix
2024-02-12 12:06:37 -08:00
Squidly271
bb5333abff Update DockerClient.php 2024-02-10 15:31:37 -05:00
tom mortensen
a6c905eb7f Merge pull request #1611 from zackspear/6.12
6.12 – fix: install key self instantiation, replace_key_job script permissions, & pro key check for update via dropdown
2024-02-08 15:47:45 -08:00
Zack Spear
2ff7230fc7 fix: replace_key_job script permissions 2024-02-08 13:24:40 -08:00
Zack Spear
8de82407a1 fix: pro key no connect update os dropdown option 2024-02-08 13:24:40 -08:00
Zack Spear
8cac67a30f fix: Install Key class self instantiate with GET request 2024-02-08 13:24:40 -08:00
tom mortensen
0893716d8c Merge pull request #1609 from zackspear/6.12
6.12 backport – Update OS tool improvements/refactors & replace key improvements
2024-02-06 17:06:48 -08:00
Zack Spear
f0db9eb5ce feat: backport latest Update OS tool 2024-02-05 16:07:24 -08:00
Zack Spear
7feea3a072 feat: backport replace key changes 2024-02-05 16:03:48 -08:00
Zack Spear
c1556a886d feat: backport state.php updates 2024-02-05 16:01:54 -08:00
Zack Spear
12a3815df0 feat: update web components to latest 2024-02-05 16:01:26 -08:00
Tom Mortensen
56fd6fe75c If no regkey use 'Tools>Registration' as start page 2024-02-01 18:50:58 -08:00
Tom Mortensen
a3fd550193 remove passing unneeded shareFruit setting 2024-02-01 18:47:24 -08:00
tom mortensen
89483d2dc8 Merge pull request #1603 from unraid/backport-feedback
Backport to 6.12 - Feedback form: change DONE button to CANCEL
2024-02-01 09:20:25 -08:00
ljm42
f763e4f6c1 Backport to 6.12 - Feedback form: change DONE button to CANCEL 2024-02-01 09:47:31 -07:00
tom mortensen
88c139a915 Merge pull request #1597 from Squidly271/patch-18
Backport: Fix PHP error when submitting diagnostics via Feedback
2024-01-30 09:21:48 -08:00
Squidly271
c24a56921f Update Feedback.php 2024-01-29 19:17:17 -05:00
tom mortensen
c7966232f1 Merge pull request #1590 from Squidly271/patch-15
Backport:  Allow CA to automatically start containers when doing multi-installs
2024-01-25 17:22:42 -08:00
Squidly271
b9014de4db Update update_container 2024-01-25 19:25:43 -05:00
tom mortensen
0e8d926d83 Merge pull request #1589 from Squidly271/patch-14
Backport Fix javascript error in library everytime a key is pressed in webGUI if vue installed
2024-01-24 12:14:13 -08:00
Squidly271
02470f48fb Update dynamix.js 2024-01-23 19:25:45 -05:00
Tom Mortensen
367960aaba remove (comment-out) development logging message 2024-01-20 08:37:14 -08:00
Tom Mortensen
fb4a7f00bf Copy syslog to flash on shutdown 2024-01-20 08:37:14 -08:00
tom mortensen
604c0704e8 Merge pull request #1585 from Squidly271/patch-11
Backport: Allow CA to override the "DONE" button appearing during multi installs / updates
2024-01-20 08:36:19 -08:00
Squidly271
c3b6179374 Update DefaultPageLayout.php 2024-01-13 19:03:05 -05:00
tom mortensen
49c0b4af72 Merge pull request #1580 from zackspear/feat/6.12-backport-new-web-components
feat/6.12 backport new web components
2024-01-10 20:41:49 -08:00
Zack Spear
4486034800 refactor(wc): update web component js to latest 2024-01-09 17:04:10 -06:00
tom mortensen
8795728382 Merge pull request #1577 from Squidly271/patch-8
Backport: PHP8 fix
2024-01-08 14:23:35 -08:00
Zack Spear
3bcd598df9 fix(wc): key install success handling 2024-01-08 13:24:41 -06:00
Squidly271
b0ddc34959 Update post_plugin_checks 2024-01-07 06:55:27 -05:00
Squidly271
7d9b68cf0e Update post_plugin_checks 2024-01-05 19:33:39 -05:00
Zack Spear
0ebcfeb931 refactor: organize translations for web components 2024-01-04 12:47:18 -06:00
Zack Spear
a21664c440 refactor: Registration page link order 2024-01-04 12:16:13 -06:00
tom mortensen
5a6a7ee90b Merge pull request #1559 from ich777/6.12
Backport ntfy.sh notification agent
2024-01-03 21:36:11 -08:00
Zack Spear
16b306e0c5 refactor: remove downgrade / update os banner 2024-01-03 16:17:20 -06:00
Zack Spear
d3fb1a2769 refactor: showchanges script allow /boot/previous for changelog parsing 2024-01-03 16:07:32 -06:00
Zack Spear
01c04682e8 refactor: default page layout with new os version web component 2024-01-03 16:07:13 -06:00
Zack Spear
a4276e665a refactor: tools link ordering for downgrade & update 2024-01-03 15:57:37 -06:00
Zack Spear
3ebfba70dc fix: upc azure & gray theme custom colors 2024-01-03 15:52:32 -06:00
Zack Spear
0a7ed0447f feat: new upc, registration page, update os page, downgrade os page, & supporting php files 2024-01-02 18:06:05 -06:00
Zack Spear
041bc5fa9c refactor: .gitignore 2024-01-02 17:45:16 -06:00
Tom Mortensen
7dd94e241d Update copyright year in footer. 2024-01-01 14:14:26 -08:00
tom mortensen
9a158ffb60 Merge pull request #1565 from unraid/backport-docker1
Backport: Docker: fix WG routes added to the correct interface
2024-01-01 13:48:01 -08:00
tom mortensen
a2d320bc87 Merge pull request #1558 from SimonFair/6.12-backport-smartctl-changes
Backport 1550 1551 1552
2024-01-01 13:47:42 -08:00
ljm42
109f9e6799 Docker: fix WG routes added to the correct interface (br0 or eth0 or bond0) 2023-12-29 12:36:14 -07:00
5acf5c6f14 Add ntfy.sh icon 2023-12-22 06:24:08 +01:00
87392ab547 Add ntfy.sh to notification agents 2023-12-22 06:24:00 +01:00
SimonFair
19b8f34641 Backport 1550 1551 1552 2023-12-21 05:37:09 +00:00
tom mortensen
452f1731df Merge pull request #1556 from SimonFair/Fix-for-os-downgrade
6.12 Fix for add VM not working
2023-12-20 11:17:17 -08:00
SimonFair
ded26b78c4 Fix for add VM not working 2023-12-20 10:44:23 +00:00
tom mortensen
8c2efe3576 Merge pull request #1545 from unraid/backport-network
Backport: bring new rc.inet features to 6.12
2023-12-18 14:41:53 -08:00
tom mortensen
f9808dbc56 Merge pull request #1547 from unraid/backport-slow-dashboard
Backport: reduce flash writes
2023-12-18 14:38:24 -08:00
tom mortensen
796524406e Merge pull request #1553 from SimonFair/Fix-for-os-downgrade
6.12 Fix for downgrade
2023-12-18 14:37:19 -08:00
SimonFair
42884e9bc5 Fix for downgrade 2023-12-18 19:15:06 +00:00
Tom Mortensen
aada9841d6 remove 'zfs_dmu_offset_next_sync=0' zfs data corruption mitigation - no longer needed 2023-12-15 15:21:50 -08:00
tom mortensen
a53f9afe0c Merge pull request #1537 from SimonFair/6.12-NVME-Selftest-fix
6.12 backport nvme selftest fix
2023-12-15 15:00:46 -08:00
ljm42
f8866cecb6 Backport: reduce flash writes
Prevents slowdown on Dashboard and Docker pages
2023-12-13 16:33:37 -07:00
ljm42
f30c282f01 Backport: bring new rc.inet features to 6.12
* interface carrier check before assigning addresses
* new "status" command to see link or IP status
* remove leading zeros from IPv4 and IPv6 addresses
2023-12-12 17:22:08 -07:00
SimonFair
82711e42bb FIx NVME Selftest 2023-12-06 21:50:14 +00:00
tom mortensen
62cee260ca Merge pull request #1531 from unraid/backport-ipv6
Backport: Fix IPv6 static address assignment
2023-12-01 10:47:18 -08:00
ljm42
c33d807fa8 Backport: Fix IPv6 static address assignment 2023-12-01 08:48:35 -07:00
ljm42
66ca926448 Backport: Fix IPv6 static address assignment 2023-11-30 16:46:03 -07:00
tom mortensen
c5f4718c08 Merge pull request #1530 from unraid/backport-ipv6
Backport: Fix IPv6 static address assignment
2023-11-30 09:45:54 -08:00
ljm42
212c49e7c1 Backport: Fix IPv6 static address assignment 2023-11-30 09:12:55 -07:00
Tom Mortensen
2d53681c99 add 'zfs_dmu_offset_next_sync=0' zfs data corruption mitigation 2023-11-29 11:05:04 -08:00
tom mortensen
fcb37cd2f6 Merge pull request #1517 from unraid/backport9
UPS: fix PHP8 error
2023-11-20 08:28:17 -08:00
ljm42
2816295782 UPS: fix PHP8 error 2023-11-20 09:19:31 -07:00
ljm42
d51c6318d9 Revert #1485 Backport to 6.12 - refactor(upc): vue3 + ts web components & improved… 2023-11-15 15:37:14 -07:00
ljm42
4db16ab50d Merge pull request #1514 from unraid/revert-1505-refactor/6.12-feedback
Revert "6.12.5 – upc feedback & fixes"
2023-11-15 15:21:38 -07:00
tom mortensen
dc04d84aa4 Revert "6.12.5 – upc feedback & fixes" 2023-11-15 13:18:58 -08:00
tom mortensen
f023ba3cbd Merge pull request #1505 from unraid/refactor/6.12-feedback
6.12.5 – upc feedback & fixes
2023-11-14 08:55:45 -08:00
Zack Spear
abf0d2390d refactor: flash_backup _var usage Wrappers include 2023-11-13 17:18:15 -08:00
Zack Spear
93f9f2c691 fix: creation of /var/tmp/unRAIDServer.txt for change log viewer 2023-11-13 16:30:36 -08:00
Zack Spear
f3c88f0fd2 refactor: spinner overlay cover entire page 2023-11-13 16:25:16 -08:00
Zack Spear
96671aa9be chore: copyright comments 2023-11-13 16:23:30 -08:00
Zack Spear
abdd7c12cb refactor: showchanges allow txt files in /boot 2023-11-13 16:21:44 -08:00
tom mortensen
24c8f7422f Merge pull request #1485 from unraid/backport4
Backport to 6.12 - refactor(upc): vue3 + ts web components & improved…
2023-11-13 14:46:26 -08:00
Zack Spear
e75e481a9a refactor: flash_backup _var usage 2023-11-13 12:48:47 -08:00
Zack Spear
edff3386b3 refactor: re-add js functions with notes for future removal 2023-11-13 12:46:19 -08:00
tom mortensen
9fd6465be0 Merge pull request #1500 from SimonFair/Backport-to-6.12---Fix-spice-auto-connection
Backport 6.12 -> Fix spice auto connect
2023-11-11 09:25:27 -08:00
SimonFair
9210d0f6ab Fix spice auto connect
Update VNC to VM Console for place holders and titles.
2023-11-11 11:40:29 +00:00
Zack Spear
c53f078cbb chore: .gitignore parity 2023-11-09 17:27:23 -08:00
Zack Spear
3324d4bd1f refactor: DefaultPageLayout clean up reboot messages + header version show changes 2023-11-09 17:21:57 -08:00
Zack Spear
264471d032 feat: Downgrade, Registration, & Update web components + accompanying php files 2023-11-09 17:20:24 -08:00
tom mortensen
588c6ec80c Merge pull request #1496 from unraid/backport8
Backport to 6.12 - always show ipvlan / macvlan setting
2023-11-07 09:53:04 -08:00
ljm42
d80995e682 always show ipvlan / macvlan setting 2023-11-06 15:52:22 -07:00
tom mortensen
1a67a68965 Merge pull request #1489 from unraid/backport7
Backport to 6.12 - Improved handling of USB-mirrored syslogs
2023-11-02 09:09:56 -07:00
tom mortensen
cd90daf483 Merge pull request #1488 from unraid/backport6
Backport to 6.12 - rc.nginx stop
2023-11-02 09:09:37 -07:00
tom mortensen
52b8a0c9f4 Merge pull request #1487 from unraid/backport5
Backport to 6.12 - rc.docker
2023-11-02 09:09:10 -07:00
tom mortensen
1f9ee76883 Merge pull request #1484 from unraid/backport3
Backport to 6.12 - Improve Downgrade process
2023-11-02 09:08:12 -07:00
tom mortensen
e88e5e4193 Merge pull request #1467 from unraid/backport2
Backport to 6.12 - fixes for CSS and WireGuard
2023-11-02 09:07:34 -07:00
tom mortensen
df808e9b07 Merge pull request #1455 from SimonFair/PCI-Override-backport
PCI Override 6.12 backport.
2023-11-02 09:06:53 -07:00
ljm42
e69a94e7cf Backport to 6.12 - Improved handling of USB-mirrored syslogs
Also needs changes to rc.M from https://github.com/unraid/webgui/pull/1449/
2023-10-31 11:10:29 -07:00
ljm42
a0349267ff Backport to 6.12 - rc.nginx stop 2023-10-31 10:43:02 -07:00
ljm42
9596b91e09 Backport to 6.12 - rc.docker 2023-10-31 08:30:51 -07:00
ljm42
e62d0e12be Backport to 6.12 - rc.docker 2023-10-31 08:24:31 -07:00
ljm42
c42cff5320 Backport to 6.12 - refactor(upc): vue3 + ts web components & improved supporting php 2023-10-30 17:56:27 -07:00
ljm42
4765dcb576 Backport to 6.12 - Improve Downgrade process 2023-10-30 17:27:07 -07:00
ljm42
61eb1ef765 Backport to 6.12 - fixes for CSS and WireGuard 2023-10-16 19:29:38 -07:00
SimonFair
ee585aab54 Fix PHP error 2023-10-15 00:01:01 +01:00
SimonFair
54c2dfbdb0 PCI Override 6.12 backport. 2023-10-11 21:44:34 +01:00
tom mortensen
2d6c7ab5ed Merge pull request #1437 from unraid/backport1
Backport fix for Docker containers on IPv6
2023-10-02 21:47:25 -07:00
ljm42
8a74adb5f2 Backport fix for Docker containers on IPv6 2023-10-01 11:30:59 -07:00
85 changed files with 2366 additions and 4485 deletions

6
.gitignore vendored
View File

@@ -63,3 +63,9 @@ share/
# Auto-generated when emhttpd/webGUI start
emhttp/languages/en_US/helptext.dot
# Auto-generated when web copmonents are built
emhttp/plugins/dynamix.my.servers/unraid-components/index.html
# development scripts
.dev-scripts/

View File

@@ -1189,7 +1189,7 @@ SSL certificate. Use this URL to access your server:
Note that use of a self-signed SSL certificate will generate a browser
warning.
Select **Strict** to enable *exclusive* use of an Unraid.net SSL
Select **Strict** to enable *exclusive* use of a myunraid.net SSL
certificate for https access (see **Provision** below). Note that a DNS
server must be reachable.
@@ -1253,10 +1253,10 @@ To adjust URLs or redirects, see the help text for "Use SSL/TLS".
:end
:mgmt_certificate_expiration_help:
**Provision** may be used to install a *free* Unraid.net SSL Certificate from
**Provision** may be used to install a *free* myunraid.net SSL Certificate from
[Let's Encrypt](https://letsencrypt.org/).
The Unraid.net SSL certificate can be used in two ways. First,
The myunraid.net SSL certificate can be used in two ways. First,
having the certificate present enables your server to respond to an
alternate URL of the form:
@@ -1270,24 +1270,20 @@ set to `*.<hash>.myunraid.net` thus validating the https connection.
You may enable this URL exclusively on your LAN by setting **Use
SSL/TLS** to **Strict**.
The second use for an Unraid.net certificate is to enable secure
remote access available through the My Servers plugin feature. Note
The second use for a myunraid.net certificate is to enable secure
remote access available through the Unraid Connect plugin feature. Note
that it is possible to use secure remote access in conjunction with
insecure local access.
After an Unraid.net SSL Certificate has been installed, two
background services are activated while the server is signed in to unraid.net:
- *updatedns* - This starts 30 seconds after server reboot has completed and contacts the Lime Technology
DNS service to register the servers local IP address. Thereafter it wakes up every 10 minutes in case
the local IP address has changed.
After a myunraid.net SSL Certificate has been installed, a
background service is activated:
- *renewcert* - This starts 60 seconds after server reboot has completed and contacts the Lime Technology
certificate renewal service to determine if your Unraid.net SSL certificate needs to be renewed.
certificate renewal service to determine if your myunraid.net SSL certificate needs to be renewed.
Thereafter it wakes up every 24 hours. If within 30 days of expiration, a new certificate is automatically
provisioned and downloaded to your server.
**Delete** may be used to delete the Unraid.net certificate file.
**Delete** may be used to delete the myunraid.net certificate file.
**nginx certificate handling details**
@@ -1295,7 +1291,7 @@ nginx makes use of two certificate files stored on the USB flash boot device:<br
- a self-signed certificate: `config/ssl/certs/<server-name>_unraid_bundle.pem`
- an Unraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
- a myunraid.net certificate: `config/ssl/certs/certificate_bundle.pem`
The self-signed SSL certificate file is automatically created when nginx
starts; and re-created if the server hostname or local TLD is changed.
@@ -1513,6 +1509,15 @@ Change this setting to YES when troubleshooting is required and it is not possib
A mirror of the syslog file is stored in the **logs** folder of the flash device.
:end
:syslog_shutdown_flash_help:
This setting is YES by default and enables the system to copy the
syslog file to the USB device on shutdown or reboot.
After rebooting, the syslog from this run will be visible on Tools >
Syslog > syslog-previous;
it will also be included in diagnostics as logs/syslog-previous.txt
:end
:confirm_reboot_help:
Choose if rebooting or powering down the server needs a confirmation checkbox.
:end

View File

@@ -27,6 +27,9 @@ if ($_SERVER['REQUEST_URI'] == '/logout') {
$error = _('Successfully logged out');
}
// If issue with license key redirect to Tools/Registration, otherwise go to start page
$start_page = (!empty(_var($var,'regCheck'))) ? 'Tools/Registration' : _var($var,'START_PAGE','Main');
$result = exec( "/usr/bin/passwd --status root");
if (($result === false) || (substr($result, 0, 6) !== "root P"))
include "$docroot/webGui/include/.set-password.php";

View File

@@ -87,7 +87,7 @@ if (file_exists("/var/run/apcupsd.pid")) {
if (count($rows)%2==1) $result[] = "<td></td><td></td></tr>";
if ($power && isset($load)) $status[5] = ($load<90 ? "<td $green>" : "<td $red>").round($power*$load/100)." W (".$status[5].")</td>";
elseif (isset($load)) $status[5] = ($load<90 ? "<td $green>" : "<td $red>").$status[5]."</td>";
$status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "<td $green>" : "<td $red>").$status[6].($freq ? " ~ $freq Hz" : "")."</td>") : $status[6];
$status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "<td $green>" : "<td $red>").$status[6].(isset($freq) ? " ~ $freq Hz" : "")."</td>") : $status[6];
}
if (empty($rows)) $result[] = "<tr><td colspan='4' style='text-align:center'>"._('No information available')."</td></tr>";

View File

@@ -124,6 +124,7 @@ function LockButton() {
}
function loadlist(init) {
timers.docker = setTimeout(function(){$('div.spinner.fixed').show('slow');},500);
docker = [];
$.get('/plugins/dynamix.docker.manager/include/DockerContainers.php',function(d) {
clearTimeout(timers.docker);
var data = d.split(/\0/);

View File

@@ -257,16 +257,14 @@ _(Template Authoring Mode)_:
:docker_authoring_mode_help:
<?if ($bridge):?>
_(Docker custom network type)_:
: <select name="DOCKER_NETWORK_TYPE">
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '1', _('ipvlan'))?>
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '', _('macvlan'))?>
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '1', _('ipvlan'), $bridge?'':'disabled')?>
<?=mk_option(_var($dockercfg,'DOCKER_NETWORK_TYPE'), '', _('macvlan'), $bridge?'':'selected')?>
</select>&nbsp;_(Please read the Help carefully)_. _(Misconfiguration can cause problems)_.
:docker_custom_network_type_help:
<?endif;?>
_(Host access to custom networks)_:
: <select name="DOCKER_ALLOW_ACCESS">
<?=mk_option(_var($dockercfg,'DOCKER_ALLOW_ACCESS'), '', _('Disabled'))?>
@@ -465,13 +463,11 @@ _(Docker LOG rotation)_:
:docker_log_rotation_active_help:
<?if ($bridge):?>
_(Docker custom network type)_:
: <?=_var($dockercfg,'DOCKER_NETWORK_TYPE')=='1' ? _('ipvlan') : _('macvlan')?>
: <?=_var($dockercfg,'DOCKER_NETWORK_TYPE')!='1' || !$bridge ? _('macvlan') : _('ipvlan')?>
:docker_custom_network_type_help:
<?endif;?>
_(Host access to custom networks)_:
: <?=_var($dockercfg,'DOCKER_ALLOW_ACCESS')=='yes' ? _('Enabled') : _('Disabled')?>

View File

@@ -51,9 +51,12 @@ $port = file_exists('/sys/class/net/br0') ? 'BR0' : (file_exists('/sys/class/net
// Docker configuration file - guaranteed to exist
$docker_cfgfile = '/boot/config/docker.cfg';
if (file_exists($docker_cfgfile) && exec("grep -Pom1 '_{$port}(_[0-9]+)?=' $docker_cfgfile")=='') {
# interface has changed, update configuration
exec("sed -ri 's/_(BR0|BOND0|ETH0)(_[0-9]+)?=/_{$port}\\2=/' $docker_cfgfile");
if (file_exists($docker_cfgfile)) {
exec("grep -Pom2 '_SUBNET_|_{$port}(_[0-9]+)?=' $docker_cfgfile",$cfg);
if (isset($cfg[0]) && $cfg[0]=='_SUBNET_' && empty($cfg[1])) {
# interface has changed, update configuration
exec("sed -ri 's/_(BR0|BOND0|ETH0)(_[0-9]+)?=/_{$port}\\2=/' $docker_cfgfile");
}
}
$defaults = @parse_ini_file("$docroot/plugins/dynamix.docker.manager/default.cfg") ?: [];
@@ -722,7 +725,7 @@ class DockerClient {
$fp = stream_socket_client('unix:///var/run/docker.sock', $errno, $errstr);
if ($fp === false) {
echo "Couldn't create socket: [$errno] $errstr";
return null;
return [];
}
$protocol = $unchunk ? 'HTTP/1.0' : 'HTTP/1.1';
$out = "$method {$api}{$url} $protocol\r\nHost:127.0.0.1\r\nConnection:Close\r\n";
@@ -979,7 +982,7 @@ class DockerClient {
$c['Id'] = $this->extractID($ct['Id']);
$c['ParentId'] = $this->extractID($ct['ParentId']);
$c['Size'] = $this->formatBytes($ct['Size']);
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize']);
$c['VirtualSize'] = $this->formatBytes($ct['VirtualSize'] ?? null);
$c['Tags'] = array_map('htmlspecialchars', $ct['RepoTags'] ?? []);
$c['Repository'] = vsprintf('%1$s/%2$s', preg_split("#[:\/]#", DockerUtil::ensureImageTag($ct['RepoTags'][0]??'')));
$c['usedBy'] = $this->usedBy($c['Id']);

View File

@@ -270,6 +270,8 @@ function xmlToCommand($xml, $create_paths=false) {
$Mode = strval($config['Mode']);
if ($confType != "device" && !strlen($containerConfig)) continue;
if ($confType == "path") {
if ( ! trim($hostConfig) || ! trim($containerConfig) )
continue;
$Volumes[] = escapeshellarg($hostConfig).':'.escapeshellarg($containerConfig).':'.escapeshellarg($Mode);
if (!file_exists($hostConfig) && $create_paths) {
@mkdir($hostConfig, 0777, true);

View File

@@ -1,8 +1,8 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2014-2023, Guilherme Jardim, Eric Schultz, Jon Panozzo.
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
* Copyright 2014-2021, Guilherme Jardim, Eric Schultz, Jon Panozzo.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -17,6 +17,7 @@ $docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.docker.manager/include/DockerClient.php";
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix', true));
// Multi-language support
@@ -44,7 +45,7 @@ if (!isset($check)) {
$DockerTemplates->getAllInfo(true);
echo " Done.";
} else {
$notify = "$docroot/webGui/scripts/notify";
$script = "$docroot/webGui/scripts/notify";
$var = @parse_ini_file("/var/local/emhttp/var.ini") ?: [];
$server = strtoupper(_var($var,'NAME','tower'));
$output = _var($notify,'docker_notify');
@@ -60,7 +61,7 @@ if (!isset($check)) {
$event = str_replace("&apos;","'",_("Docker")." - $name [$new]");
$subject = str_replace("&apos;","'",sprintf(_("Notice [%s] - Version update %s"),$server,$new));
$description = str_replace("&apos;","'",sprintf(_("A new version of %s is available"),$name));
exec("$notify -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Docker' -x");
}
}
}

View File

@@ -179,11 +179,16 @@ foreach (explode('*',rawurldecode($argv[1])) as $value) {
$startContainer = false;
if (!empty($oldContainerInfo) && !empty($oldContainerInfo['State']) && !empty($oldContainerInfo['State']['Running'])) {
// since container was already running, put it back it to a running state after update
$cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
$startContainer = true;
// attempt graceful stop of container first
stopContainer_nchan($Name);
}
if ( ($argv[2]??null) == "ca_docker_run_override" )
$startContainer = true;
if ( $startContainer )
$cmd = str_replace('/docker create ', '/docker run -d ', $cmd);
// force kill container if still running after 10 seconds
if (empty($_GET['communityApplications'])) removeContainer_nchan($Name);
execCommand_nchan($cmd);

View File

@@ -1,62 +1,14 @@
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
}
.ui-dropdownchecklist .ui-state-default{
background:#f2f2f2;
border:none;
box-shadow:none;
outline:none;
cursor:pointer;
height:2.2rem;
line-height:2.2rem;
}
.ui-dropdownchecklist-group{
font-weight:normal;
font-style:italic;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector{
border:1px solid #1c1c1c;
display:inline-block;
cursor:pointer;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector-wrapper{
vertical-align:middle;
font-size:0;
}
.ui-widget-header{
border:none;
background:#e3e3e3;
color:#1c1c1c;
font-weight:bold;
}
.ui-widget-content{
border:1px solid #1c1c1c;
background:#f2f2f2;
color:#1c1c1c;
.ui-state-active{
background:#e8e8e8;
}
.ui-dropdownchecklist-dropcontainer{
background:#f2f2f2;
border:1px solid #1c1c1c;
}
.ui-state-disabled{
color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5;
}
.ui-dropdownchecklist-indent{
padding-left:7px;
}
.ui-dropdownchecklist-text{
color:#1c1c1c;
font-size:1.3rem;
}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
background:#f2f2f2;
border:0px;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
.ui-state-active{background:#e8e8e8}
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
.ui-dropdownchecklist-indent{padding-left:7px}
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}

View File

@@ -1,62 +1,14 @@
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
}
.ui-dropdownchecklist .ui-state-default{
background:#1c1c1c;
border:none;
box-shadow:none;
outline:none;
cursor:pointer;
height:2.2rem;
line-height:2.2rem;
}
.ui-dropdownchecklist-group{
font-weight:normal;
font-style:italic;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector{
border:1px solid #e5e5e5;
display:inline-block;
cursor:pointer;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector-wrapper{
vertical-align:middle;
font-size:0;
}
.ui-widget-header{
border:none;
background:#2b2b2b;
color:#f2f2f2;
font-weight:bold;
}
.ui-widget-content{
border:1px solid #e5e5e5;
background:#1c1c1c;
color:#f2f2f2;
.ui-state-active{
background:#262626;
}
.ui-dropdownchecklist-dropcontainer{
background:#1c1c1c;
border:1px solid #e5e5e5;
}
.ui-state-disabled{
color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5;
}
.ui-dropdownchecklist-indent{
padding-left:7px;
}
.ui-dropdownchecklist-text{
color:#f2f2f2;
font-size:1.3rem;
}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
background:#1c1c1c;
border:0px;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
.ui-state-active{background:#262626}
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
.ui-dropdownchecklist-indent{padding-left:7px}
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}

View File

@@ -1,62 +1,14 @@
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
}
.ui-dropdownchecklist .ui-state-default{
background:#1c1c1c;
border:none;
box-shadow:none;
outline:none;
cursor:pointer;
height:2.2rem;
line-height:2.2rem;
}
.ui-dropdownchecklist-group{
font-weight:normal;
font-style:italic;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector{
border:1px solid #e5e5e5;
display:inline-block;
cursor:pointer;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector-wrapper{
vertical-align:middle;
font-size:0;
}
.ui-widget-header{
border:none;
background:#2b2b2b;
color:#f2f2f2;
font-weight:bold;
}
.ui-widget-content{
border:1px solid #e5e5e5;
background:#1c1c1c;
color:#f2f2f2;
.ui-state-active{
background:#262626;
}
.ui-dropdownchecklist-dropcontainer{
background:#1c1c1c;
border:1px solid #e5e5e5;
}
.ui-state-disabled{
color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5;
}
.ui-dropdownchecklist-indent{
padding-left:7px;
}
.ui-dropdownchecklist-text{
color:#f2f2f2;
font-size:1.3rem;
}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
background:#1c1c1c;
border:0px;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
.ui-dropdownchecklist .ui-state-default{background:#1c1c1c;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector{border:1px solid #e5e5e5;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
.ui-widget-header{border:none;background:#2b2b2b;color:#f2f2f2;font-weight:bold}
.ui-widget-content{border:1px solid #e5e5e5;background:#1c1c1c;color:#f2f2f2}
.ui-state-active{background:#262626}
.ui-dropdownchecklist-dropcontainer{background:#1c1c1c;border:1px solid #e5e5e5}
.ui-state-disabled{color:#f2f2f2;border-color:#6c6c6c;background:#262626;opacity:0.5}
.ui-dropdownchecklist-indent{padding-left:7px}
.ui-dropdownchecklist-text{color:#f2f2f2;font-size:1.3rem}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#1c1c1c;border:0px}

View File

@@ -1,62 +1,14 @@
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{
font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{
color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)
}
.ui-dropdownchecklist .ui-state-default{
background:#f2f2f2;
border:none;
box-shadow:none;
outline:none;
cursor:pointer;
height:2.2rem;
line-height:2.2rem;
}
.ui-dropdownchecklist-group{
font-weight:normal;
font-style:italic;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector{
border:1px solid #1c1c1c;
display:inline-block;
cursor:pointer;
padding:1px 9px 1px 8px;
}
.ui-dropdownchecklist-selector-wrapper{
vertical-align:middle;
font-size:0;
}
.ui-widget-header{
border:none;
background:#e3e3e3;
color:#1c1c1c;
font-weight:bold;
}
.ui-widget-content{
border:1px solid #1c1c1c;
background:#f2f2f2;
color:#1c1c1c;
.ui-state-active{
background:#e8e8e8;
}
.ui-dropdownchecklist-dropcontainer{
background:#f2f2f2;
border:1px solid #1c1c1c;
}
.ui-state-disabled{
color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5;
}
.ui-dropdownchecklist-indent{
padding-left:7px;
}
.ui-dropdownchecklist-text{
color:#1c1c1c;
font-size:1.3rem;
}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{
background:#f2f2f2;
border:0px;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button{font-family:clear-sans;font-size:1.1rem;font-weight:bold;letter-spacing:2px;text-transform:uppercase;margin:10px 12px 10px 0;padding:9px 18px;text-decoration:none;white-space:nowrap;cursor:pointer;outline:none;border-radius:4px;border:0;color:#ff8c2f;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 0 no-repeat,-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#e22828),to(#e22828)) 0 100% no-repeat,-webkit-gradient(linear,left bottom,left top,from(#ff8c2f),to(#ff8c2f)) 100% 100% no-repeat;background:linear-gradient(90deg,#e22828 0,#ff8c2f) 0 0 no-repeat,linear-gradient(90deg,#e22828 0,#ff8c2f) 0 100% no-repeat,linear-gradient(0deg,#e22828 0,#e22828) 0 100% no-repeat,linear-gradient(0deg,#ff8c2f 0,#ff8c2f) 100% 100% no-repeat;background-size:100% 2px,100% 2px,2px 100%,2px 100%}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset button:hover{color:#f2f2f2;background:-webkit-gradient(linear,left top,right top,from(#e22828),to(#ff8c2f));background:linear-gradient(90deg,#e22828 0,#ff8c2f)}
.ui-dropdownchecklist .ui-state-default{background:#f2f2f2;border:none;box-shadow:none;outline:none;cursor:pointer;height:2.2rem;line-height:2.2rem}
.ui-dropdownchecklist-group{font-weight:normal;font-style:italic;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector{border:1px solid #1c1c1c;display:inline-block;cursor:pointer;padding:1px 9px 1px 8px}
.ui-dropdownchecklist-selector-wrapper{vertical-align:middle;font-size:0}
.ui-widget-header{border:none;background:#e3e3e3;color:#1c1c1c;font-weight:bold}
.ui-widget-content{border:1px solid #1c1c1c;background:#f2f2f2;color:#1c1c1c}
.ui-state-active{background:#e8e8e8}
.ui-dropdownchecklist-dropcontainer{background:#f2f2f2;border:1px solid #1c1c1c}
.ui-state-disabled{color:#1c1c1c;border-color:#a2a2a2;background:#e8e8e8;opacity:0.5}
.ui-dropdownchecklist-indent{padding-left:7px}
.ui-dropdownchecklist-text{color:#1c1c1c;font-size:1.3rem}
.ui-dropdownchecklist .ui-widget-content .ui-state-default{background:#f2f2f2;border:0px}

View File

@@ -1,10 +1,10 @@
Menu="About"
Menu="About:30"
Type="xmenu"
Title="Registration"
Icon="icon-registration"
Tag="pencil"
---
<?PHP
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
@@ -15,239 +15,6 @@ Tag="pencil"
* all copies or substantial portions of the Software.
*/
?>
<?
function my_time_any($time) {
return $time ? _(my_time($time),0) : _('Anytime');
}
function my_time_now($time) {
return $time ? _(my_time($time),0) : _('Unknown');
}
?>
<style>
span.thanks{padding-left:12px;color:#6FA239;font-weight:bold;}
span.thanks.red{color:#F0000C;}
div.device{padding:0 12px;font-weight:normal;font-style:italic;}
div.remark{padding:0 12px;text-align:justify;}
</style>
<?if ( (strstr($var['regTy'], "unregistered")) or ($var['regTy']=="Trial") or (strstr($var['regTy'], "no connection")) or (strstr($var['regTy'], "withdrawn")) or (strstr($var['regTy'], "expired")) ):?>
<span class="thanks">_(Thank you for trying Unraid OS)_!</span>
<?elseif ( ($var['regTy']=="Basic") or ($var['regTy']=="Plus") or ($var['regTy']=="Pro") ):?>
<span class="thanks">_(Thank you for choosing Unraid OS)_!</span>
<?endif;?>
<?if (strstr($var['regTy'], "unregistered")):?>
<div markdown="1" class="remark">
:registration_1_plug:
Your server will not be usable until you purchase a Registration key or install a free 30-day *Trial* key. A *Trial*
key provides all the functionality of a *Pro* Registration key.
Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device
at least 1GB in size (min 4GB recommended).
Note: USB memory card readers are generally **not** supported because most do not present unique serial numbers.
:end
</div>
<?endif;?>
<?if ($var['regTy']=="Trial"):?>
<div markdown="1" class="remark">
:registration_3_plug:
Your *Trial* key includes all the functionality and device support of a *Pro* Registration key.
After your *Trial* key has reached expiration, your server **still functions normally** until the next time you **Stop** the array.
At that point, you may either purchase a Registration key, or request a *Trial* extension.
:end
</div>
<?endif;?>
<?if (strstr($var['regTy'], "no connection")):?>
<div markdown="1" class="remark">
<span class='red-text'>_(Cannot connect to key-server)_!</span>
_(Your *Trial* key requires an internet connection)_. _(Please check your)_ [_(Network Settings)_](NetworkSettings).
</div>
<?endif;?>
<?if (strstr($var['regTy'], "withdrawn")):?>
<div markdown="1" class="remark">
<span class='red-text'>_(Release has been withdrawn)_!</span>
_(This release has been withdrawn for use with *Trial* keys)_.
</div>
<?endif;?>
<?if (strstr($var['regTy'], "expired")):?>
<div markdown="1" class="remark">
<span class='red-text'>_(Your *Trial* key has expired)_.</span>
:registration_4_plug:
To continue using Unraid OS you may purchase a Registration key. Alternately, you may request a *Trial* extension key.
Most *Trial* extension requests are processed immediately but please allow up to one business day to receive your *Trial* extension key.
:end
</div>
<?endif;?>
<?if (strstr($var['regTy'], "invalid installation")):?>
<span class='thanks red'>_(Invalid *Trial* Installation)_</span>
<div markdown="1" class="remark">
:registration_5_plug:
It is not possible to use a *Trial* key with an existing Unraid OS installation.
You may purchase a Registration key corresponding to this USB Flash device to continue using this installation.
For more information, please [Contact Support](https://lime-technology.com/contact).
:end
</div>
<?endif;?>
<?if (strstr($var['regTy'], "missing")):?>
<span class='thanks red'>_(Missing Key File)_</span>
<div markdown="1" class="remark">
:registration_6_plug:
It appears that your Registration key file is corrupted or missing. The key file should be located in the
[config](/Registration/Browse?dir&#61;/boot/config) directory on your USB Flash boot device.
If you do not have a backup copy of your Registration key file, [Contact Support](https://lime-technology.com/contact).
If this was a *Trial* installation, you may purchase a Registration key.
:end
</div>
<?endif;?>
<?if (strstr($var['regTy'], "invalid key")):?>
<span class='thanks red'>_(The registered GUID does not match the USB Flash boot device GUID)_</span>
<?if (strstr($var['regTy'], "Trial")):?>
<div markdown="1" class="remark">
:registration_7_plug:
*Trial* installations are only valid with the originally registered USB Flash device.
To continue using this installation with this USB Flash device, you may purchase a Registration key.
:end
</div>
<?else:?>
<div markdown="1" class="remark">
:registration_8_plug:
The Registration key file does not correspond to the USB Flash boot device.
Please copy the correct key file to the [config](/Registration/Browse?dir&#61;/boot/config) directory
on your USB Flash boot device. If you do not have a backup copy of your key file, [Contact Support](https://lime-technology.com/contact).
If you want to replace your Registration key with a new key bound to this USB Flash device, click Replace Key below. An original key may be
replaced anytime. Thereafter, a replacement key may be replaced again after one year has passed. If you require
another replacement key sooner, [Contact Support](https://lime-technology.com/contact).
**Note:** Replacing a Registration key results in permanently *blacklisting* the previous USB Flash GUID.
:end
</div>
<?endif;?>
<?endif;?>
<?if (strstr($var['regTy'], "blacklisted")):?>
<span class='thanks red'>_(Blacklisted USB Flash GUID)_</span>
<div markdown="1" class="remark">
:registration_9_plug:
This USB Flash boot device has been *blacklisted*. This can occur as a result of transfering your Registration key to
a replacement USB Flash device, and you are currently booted from your old USB Flash device.
A USB Flash device may also be *blacklisted* if there is no serial number, or if we discover the serial number
is not unique (this is common with USB card readers).
For more information, please [Contact Support](https://lime-technology.com/contact).
:end
</div>
<?endif;?>
<?if ( ( !(strstr($var['regTy'], "invalid key")) and ((strstr($var['regTy'], "Trial"))) ) || (strstr($var['regTy'], "no connection")) || (strstr($var['regTy'], "withdrawn")) ):?>
_(***Trial*** key expires on)_:
: <?=my_time_now($var['regTm2'])?>
<?endif;?>
<?if ( strstr($var['regTy'], "invalid installation") || ( (strstr($var['regTy'], "invalid key")) && (strstr($var['regTy'], "Trial")) )):?>
_(Expiration)_:
: <?=my_time_now($var['regTm2'])?>
<?endif;?>
<?if ( (strstr($var['regTy'], "invalid installation")) || (strstr($var['regTy'], "invalid key")) || ($var['regTy']=="Basic") || ($var['regTy']=="Plus") || ($var['regTy']=="Pro") ):?>
_(Registered to)_:
: <?=htmlspecialchars($var['regTo'])?>
_(Registered on)_:
: <?=my_time_now($var['regTm'])?>
<?endif;?>
<?if ( (strstr($var['regTy'], "invalid installation")) or ( (strstr($var['regTy'], "invalid key")) and (!(strstr($var['regTy'], "Trial")))) ):?>
_(Registered GUID)_:
: <?=$var['regGUID']?>
<?endif;?>
<?if (strstr($var['regTy'], "flash device error")):?>
<span class='thanks red'>_(Error accessing your physical USB Flash boot device)_</span>
<div markdown="1" class="remark">
_(There is a physical problem accessing your USB Flash boot device)_. _(Please)_ [Contact Support](https://lime-technology.com/contact).
_(Flash GUID)_:
: _(Error code)_: <?=$var['regCheck']?>
<?else:?>
_(Flash GUID)_:
: <?=$var['flashGUID']?>
<?endif;?>
_(Flash Vendor)_:
: <?=$var['flashVendor']?>
_(Flash Product)_:
: <?=$var['flashProduct']?>
<?if ( ((strstr($var['regTy'], "invalid key")) and !(strstr($var['regTy'], "Trial"))) || ($var['regTy']=="Basic") || ($var['regTy']=="Plus") || ($var['regTy']=="Pro") ):?>
_(Replaceable)_:
: <?=my_time_any($var['regTm2'])?>
<?endif;?>
<?if ( !(strstr($var['regTy'], "flash device error")) || !(strstr($var['regTy'], "blacklisted")) ):?>
<div class="device"><?=sprintf(_("This server has %s attached storage device".($var['deviceCount']==1?'.':'s.')),$var['deviceCount'])?></div>
<?endif;?>
<unraid-upc-trigger></unraid-upc-trigger>
<unraid-i18n-host>
<unraid-registration></unraid-registration>
</unraid-i18n-host>

View File

@@ -0,0 +1,23 @@
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
$var = (array)parse_ini_file('state/var.ini');
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/webGui/include/Helpers.php";
extract(parse_plugin_cfg('dynamix',true));
require_once "$docroot/plugins/dynamix.my.servers/include/state.php";
$serverState = new ServerState();
header('Content-type: application/json');
echo $serverState->getServerStateJson();

View File

@@ -1,129 +1,62 @@
<!-- myservers1 -->
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<style>
#header {
z-index: 102 !important;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
z-index: 102 !important;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
vue-userprofile,
unraid-user-profile {
font-size: 16px;
margin-left: auto;
height: 100%;
#header unraid-i18n-host {
font-size: 16px;
margin-left: auto;
height: 100%;
}
unraid-launchpad,
unraid-promo {
position: relative;
z-index: 10001;
/**
* Tools page, rotate the Downgrade icon to prevent needing to add a new icon to the icon font.
* The pseudo element is targeted here otherwise the rotation of the span would mess up spacing with the text.
*/
a[href="/Tools/Downgrade"] .icon-update:before {
display: inline-block; /* required otherwise the rotation won't work */
rotate: 180deg;
}
</style>
<?
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
$myservers = file_exists($myservers_flash_cfg_path) ? @parse_ini_file($myservers_flash_cfg_path,true) : [];
<?php
// Set the path for the local manifest file
$localManifestFile = '/usr/local/emhttp/plugins/dynamix.my.servers/unraid-components/manifest.json';
$ALLOWED_UPC_ENV_VALS = [
'production',
'staging',
'stagingLogs',
'development',
'local',
'preview',
];
$ALLOWED_UPC_ENV_PREVIEW_CNAME = '.d1eohvtyc6gnee.amplifyapp.com/';
// Load the local manifest
$localManifest = json_decode(file_get_contents($localManifestFile), true);
// defaults
$computedCookieValue = $_COOKIE['UPC_ENV'] ?? '';
$previewUrl = '';
$isPreview = strpos($computedCookieValue, 'preview::');
// extract preview src url
if ($isPreview !== false) {
list($computedCookieValue, $previewUrl) = explode('::', $computedCookieValue);
// prevent unauthoraized URLs for previews
$isPreviewAllowed = strpos($previewUrl, $ALLOWED_UPC_ENV_PREVIEW_CNAME);
if (!$isPreviewAllowed) {
$computedCookieValue = '';
$previewUrl = '';
}
$searchText = 'unraid-components.client.mjs';
$fileValue = null;
foreach ($localManifest as $key => $value) {
if (strpos($key, $searchText) !== false && isset($value["file"])) {
$fileValue = $value["file"];
break;
}
}
// finalize cookie value
$UPC_ENV_CK = in_array($computedCookieValue, $ALLOWED_UPC_ENV_VALS)
? $computedCookieValue
: null;
// Determine what source we should use for web components
if (!file_exists('/usr/local/sbin/unraid-api')) { // When NOT using the plugin we should load the UPC from the file system unless $UPC_ENV_CK exists.
$UPC_ENV = $UPC_ENV_CK ?? 'local';
if ($fileValue !== null) {
$prefixedPath = '/plugins/dynamix.my.servers/unraid-components/';
echo '<script src="' . $prefixedPath . $fileValue . '"></script>';
} else {
$UPC_ENV = $UPC_ENV_CK ?? 'production';
echo '<script>console.error("%cNo matching key containing \'' . $searchText . '\' found.", "font-weight: bold; color: white; background-color: red");</script>';
}
$upcLocalSrc = autov('/plugins/dynamix.my.servers/webComps/unraid.min.js', true);
switch ($UPC_ENV) {
case 'production':
$upcSrc = 'https://registration.unraid.net/webComps/unraid.min.js';
break;
case 'staging':
$upcSrc = 'https://registration-dev.unraid.net/webComps/unraid.min.js';
break;
case 'stagingLogs':
$upcSrc = 'https://registration-dev-logs.unraid.net/webComps/unraid.min.js';
break;
case 'development':
$upcSrc = 'https://launchpad.unraid.test:6969/webComps/unraid.js?t=' . time();
break;
case 'preview':
$upcSrc = $previewUrl . 'webComps/unraid.min.js';
break;
default: // load from webGUI filesystem.
$upcSrc = $upcLocalSrc;
break;
}
// add the intended web component source to the DOM
echo '<script id="unraid-wc" defer src="' . $upcSrc . '"></script>';
?>
<script type="text/javascript">
const upcEnvCookie = "<?=$UPC_ENV_CK??''?>";
if (upcEnvCookie) console.debug('[UPC_ENV] ✨', upcEnvCookie);
// If the UPC isn't defined after 3secs inject UPC via
setTimeout(() => {
// UPC exists do nothing
if (window.customElements.get('unraid-user-profile')) return;
console.log('[UPC] Fallback to filesystem src 😖');
const el = document.createElement('script');
el.type = 'text/javascript';
el.src = '<?=$upcLocalSrc?>';
document.head.appendChild(el);
return upcEnv('local', false, true); // set session cookie to prevent delayed loads of UPC
}, 3000);
function upcEnv(str, reload = true, session = false) { // overwrite upc src
const ckName = 'UPC_ENV';
const ckDate = new Date();
const ckDays = 30;
ckDate.setTime(ckDate.getTime()+(ckDays*24*60*60*1000));
const ckExpire = `expires=${session ? 0 : ckDate.toGMTString()};`;
if (!str) { // if no str param provided we remove the cookie to fallback to the enviroment's default JS source
console.log(`✨ ${ckName} removed…reloading ♻️ `);
document.cookie = `${ckName}=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT`;
return window.location.reload();
}
if (reload) {
console.log(`✨ ${ckName} set…reloading ✨ `);
setTimeout(() => {
window.location.reload();
}, 2000);
} else {
console.log(`✨ ${ckName}=${str} for session ✨ `);
}
return document.cookie = `${ckName}=${str}; path=/; ${ckExpire}`;
};
</script>
<!-- /myservers1 -->

View File

@@ -1,648 +1,36 @@
<!-- myservers2 -->
<?
// add 'ipaddr' function for 6.9 backwards compatibility
if (!function_exists('ipaddr')) {
function ipaddr($ethX='eth0', $prot=4) {
global $$ethX;
switch ($$ethX['PROTOCOL:0']) {
case 'ipv4':
return $$ethX['IPADDR:0'];
case 'ipv6':
return $$ethX['IPADDR6:0'];
case 'ipv4+ipv6':
switch ($prot) {
case 4: return $$ethX['IPADDR:0'];
case 6: return $$ethX['IPADDR6:0'];
default:return [$$ethX['IPADDR:0'],$$ethX['IPADDR6:0']];}
default:
return $$ethX['IPADDR:0'];
}
}
}
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once("$docroot/plugins/dynamix.my.servers/include/state.php");
require_once("$docroot/plugins/dynamix.my.servers/include/translations.php");
$upc_translations = [
($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US' => [
'getStarted' => _('Get Started'),
'signIn' => _('Sign In'),
'signUp' => _('Sign Up'),
'signInUp' => _('Sign In / Up'),
'signInUnraidNetAccount' => _('Sign In with Unraid.net Account'),
'signOut' => _('Sign Out'),
'error' => _('Error'),
'fixError' => _('Fix Error'),
'closeLaunchpad' => _('Close Launchpad and continue to webGUI'),
'installPlugin' => _('Install Plugin'),
'noThanks' => _('No thanks'),
'closePromo' => _('Close Connect details and continue to webGUI'),
'promoHeading' => _('Enhance your Unraid experience with these<br> Connect (BETA) features'),
'learnMore' => _('Learn more'),
'checkoutTheMyServersDocs' => _('Checkout the Connect docs'),
'popUp' => _('Pop-up'),
'close' => _('Close'),
'backToPopUp' => sprintf(_('Back to %s'), _('Pop-up')),
'closePopUp' => sprintf(_('Close %s'), _('Pop-up')),
'contactSupport' => _('Contact Support'),
'lanIp' => sprintf(_('Click to copy LAN IP %s'), '{0}'),
'lanIpCopied' => _('LAN IP Copied'),
'continueToUnraid' => _('Continue to Unraid'),
'description' => _('Description'),
'year' => _('year'),
'years' => _('years'),
'month' => _('month'),
'months' => _('months'),
'day' => _('day'),
'days' => _('days'),
'hour' => _('hour'),
'hours' => _('hours'),
'minute' => _('minute'),
'minutes' => _('minutes'),
'second' => _('second'),
'seconds' => _('seconds'),
'ago' => _('ago'),
'basicPlusPro' => [
'heading' => _('Thank you for choosing Unraid OS and Connect').'!',
'message' => [
'registered' => _('Register for Connect by signing in to Unraid.net'),
'upgradeEligible' => _('To support more storage devices as your server grows click Upgrade Key'),
],
],
'actions' => [
'purchase' => _('Purchase Key'),
'upgrade' => _('Upgrade Key'),
'recover' => _('Recover Key'),
'replace' => _('Replace Key'),
'replaceIneligible' => _('Replace Key Ineligible'),
'extend' => _('Extend Trial'),
'startTrial' => _('Start Trial'),
'signOutUnraidNet' => _('Sign Out of Unraid.net'),
'redeemActivationCode' => _('Redeem Activation Code'),
],
'upc' => [
'avatarAlt' => '{0} '._('Avatar'),
'confirmClosure' => _('Confirm closure then continue to webGUI'),
'closeDropdown' => _('Close dropdown'),
'openDropdown' => _('Open dropdown'),
'pleaseConfirmClosureYouHaveOpenPopUp' => _('Please confirm closure').'. '._('You have an open pop-up').'.',
'trialHasExpiredSeeOptions' => _('Trial has expired see options below'),
'errorCertRequiresSignIn' => _('Sign In before your Unraid.net SSL certificate expires'),
'removeMyServersPlugin' => _('Remove Connect plugin'),
'continueUsingMyServers' => _('Continue using Connect'),
'confirmMyServersPluginRemoval' => _('Confirm Connect plugin removal'),
'removingMyServersPlugin' => _('Removing Connect plugin…'),
'enhanceYourExperienceWithMyServers' => _('Enhance your experience with Connect'),
'lanIpCopied' => _('LAN IP Copied'),
'installingMyServers' => _('Installing Connect (beta)'),
"updatePlugin" => _('Update Plugin'),
"updatingMyServers" => _('Updating Connect (beta)'),
'thankYouForInstallingMyServers' => _('Thank you installing Connect') . '!',
'connectYourUnraidnetAccountToGetStarted' => _('Connect your Unraid.net account to get started'),
'noRemoteApikeyRegisteredWithPlg' => [
'heading' => _('Connect Error'),
'msg' => _('Unraid.net re-authentication required'),
],
'errorTooManyDisks' => [
'heading' => 'Too many devices',
'msg' => [
'base' => 'You must upgrade your key to support more devices.',
'basic' => 'Your Basic key supports 6 devices.',
'plus' => 'Your Plus key supports 12 devices.',
],
],
'extraLinks' => [
'newTab' => sprintf(_('Opens %s in new tab'), '{0}'),
'myServers' => _('Go to Connect'),
'forums' => _('Unraid Forums'),
'settings' => [
'text' => _('Settings'),
'title' => _('Settings > Management Access • Unraid.net'),
],
],
'meta' => [
'trial' => [
'active' => [
'date' => sprintf(_('Trial key expires at %s'), '{date}'),
'timeDiff' => sprintf(_('Trial expires in %s'), '{timeDiff}'),
],
'expired' => [
'date' => sprintf(_('Trial key expired at %s'), '{date}'),
'timeDiff' => sprintf(_('Trial expired %s'), '{timeDiff}'),
],
],
'uptime' => [
'date' => sprintf(_('Server up since %s'), '{date}'),
'readable' => sprintf(_('Uptime %s'), '{timeDiff}'),
],
],
'myServers' => [
'heading' => _('Connect'),
'beta' => _('beta'),
'restarting' => _('Restarting…'),
'errors' => [
'unraidApi' => [
'heading' => _('Unraid API Error'),
'message' => _('Failed to connect to Unraid API'),
],
'myServers' => [
'heading' => _('Connect Error'),
'message' => _('Please wait a moment and reload the page'),
],
],
'closeDetails' => _('Close Details'),
'loading' => _('Loading Connect data'),
'displayingLastKnown' => _('Displaying last known server data'),
'mothership' => [
'connected' => _('Connected'),
'notConnected' => _('Disconnected'),
],
'accessLabels' => [
'current' => _('Current server'),
'local' => _('Local access'),
'offline' => _('Server Offline'),
'remote' => _('Remote access'),
'unavailable' => _('Access unavailable'),
],
'api' => [
'start' => _('Restart unraid-api'),
'startTitle' => _('Executes `unraid-api start`; no terminal needed'),
'stop' => _('Stop unraid-api'),
],
],
'opensNewHttpsWindow' => [
'base' => sprintf(_('Opens new HTTPS window to %s'), '{0}'),
'signIn' => sprintf(_('Opens new HTTPS window to %s'), _('Sign In')),
'signOut' => sprintf(_('Opens new HTTPS window to %s'), _('Sign Out')),
'purchase' => sprintf(_('Opens new HTTPS window to %s'), _('Purchase Key')),
'upgrade' => sprintf(_('Opens new HTTPS window to %s'), _('Upgrade Key')),
],
'signInActions' => [
'resolve' => _('Sign In to resolve'),
'purchaseKey' => _('Sign In to Purchase Key'),
'purchaseKeyOrExtendTrial' => '@:upc.signInActions.purchaseKey or @:actions.extend',
],
],
'stateData' => [
'ENOKEYFILE' => [
'humanReadable' => _('No Keyfile'),
'heading' => _("Let's unleash your hardware").'!',
'message' => '<p>'._('Your server will not be usable until you purchase a Registration key or install a free 30-day Trial key').'. '._('A Trial key provides all the functionality of a Pro Registration key').'.</p><p>'._('Registration keys are bound to your USB Flash boot device serial number (GUID)').'. '._('Please use a high quality name brand device at least 1GB in size (min 4GB recommended)').'.</p><p>'._('Note: USB memory card readers are generally not supported because most do not present unique serial numbers').'.</p>',
],
'TRIAL' => [
'humanReadable' => _('Trial'),
'heading' => _('Thank you for choosing Unraid OS').'!',
'message' => _('Your Trial key includes all the functionality and device support of a Pro key').'. '._('After your Trial has reached expiration your server still functions normally until the next time you Stop the array or reboot your server').'. '._('At that point you may either purchase a license key or request a Trial extension').'.',
'_extraMsg' => sprintf(_('You have %s remaining on your Trial key'), '{parsedExpireTime}'),
],
'EEXPIRED' => [
'humanReadable' => _('Trial Expired'),
'heading' => _('Your Trial has expired'),
'message' => [
'base' => _('To continue using Unraid OS you may purchase a license key').'. ',
'extensionNotEligible' => _('You have used all your Trial extensions').'. @:stateData.EEXPIRED.message.base',
'extensionEligible' => '@:stateData.EEXPIRED.message.base '._('Alternately, you may request a Trial extension').'.',
],
],
'BASIC' => [
'humanReadable' => _('Basic'),
],
'PLUS' => [
'humanReadable' => _('Plus'),
],
'PRO' => [
'humanReadable' => _('Pro'),
],
'EGUID' => [
'humanReadable' => _('GUID Error'),
'error' => [
'heading' => _('Registration key / GUID mismatch'),
'message' => [
'default' => _('The license key file does not correspond to the USB Flash boot device').'. '._('Please copy the correct key file to the */config* directory on your USB Flash boot device or choose Purchase Key').'.',
'replacementIneligible' => _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months').'.',
'replacementEligible' => _('The license key file does not correspond to the USB Flash boot device').'. '._('Please copy the correct key file to the */config* directory on your USB Flash boot device or choose Purchase Key or Replace Key').'.',
'blacklisted' => _('Your Unraid registration key is ineligible for replacement as it is blacklisted') . '.',
],
],
],
'ENOKEYFILE2' => [
'humanReadable' => _('Missing key file'),
'error' => [
'heading' => '@:stateData.ENOKEYFILE2.humanReadable',
'message' => _('It appears that your license key file is corrupted or missing').'. '._('The key file should be located in the */config* directory on your USB Flash boot device').'. '._('If you do not have a backup copy of your license key file you may install the Connect (beta) plugin to attempt to recover your key').'. '._('If this was an expired Trial installation, you may purchase a license key').'.',
],
],
'ETRIAL' => [
'humanReadable' => _('Invalid installation'),
'error' => [
'heading' => '@:stateData.ETRIAL.humanReadable',
'message' => _('It is not possible to use a Trial key with an existing Unraid OS installation').'. '._('You may purchase a license key corresponding to this USB Flash device to continue using this installation').'.',
],
],
'ENOKEYFILE1' => [
'humanReadable' => _('No Keyfile'),
'error' => [
'heading' => _('No USB flash configuration data'),
'message' => _('There is a problem with your USB Flash device'),
],
],
'ENOFLASH' => [
'humanReadable' => _('No Flash'),
'error' => [
'heading' => _('Cannot access your USB Flash boot device'),
'message' => _('There is a physical problem accessing your USB Flash boot device'),
],
],
'EGUID1' => [
'humanReadable' => _('Multiple License Keys Present'),
'error' => [
'heading' => '@:stateData.EGUID1.humanReadable',
'message' => _('There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device').'. '._('Please remove all key files except the one you want to replace from the */config* directory on your USB Flash boot device').'. '._('Alternately you may purchase a license key for this USB flash device').'. '._('If you want to replace one of your license keys with a new key bound to this USB Flash device please first remove all other key files first').'.',
],
],
'EBLACKLISTED' => [
'humanReadable' => _('BLACKLISTED'),
'error' => [
'heading' => _('Blacklisted USB Flash GUID'),
'message' => _('This USB Flash boot device has been blacklisted').'. '._('This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device').'. '._('A USB Flash device may also be blacklisted if we discover the serial number is not unique this is common with USB card readers').'.',
],
],
'EBLACKLISTED1' => [
'humanReadable' =>'@:stateData.EBLACKLISTED.humanReadable',
'error' => [
'heading' => _('USB Flash device error'),
'message' => _('This USB Flash device has an invalid GUID').'. '._('Please try a different USB Flash device').'.',
],
],
'EBLACKLISTED2' => [
'humanReadable' => '@:stateData.EBLACKLISTED.humanReadable',
'error' => [
'heading' => _('USB Flash has no serial number'),
'message' => '@:stateData.EBLACKLISTED.error.message',
],
],
'ENOCONN' => [
'humanReadable' => _('Trial Requires Internet Connection'),
'error' => [
'heading' => _('Cannot validate Unraid Trial key'),
'message' => _('Your Trial key requires an internet connection').'. '._('Please check Settings > Network').'.',
],
],
'STALE' => [
'humanReadable' => _('Stale'),
'error' => [
'heading' => _('Stale Server'),
'message' => _('Please refresh the page to ensure you load your latest configuration'),
],
],
],
'regWizPopUp' => [
'regWiz' => _('Registration Wizard'),
'toHome' => _('To Registration Wizard Home'),
'continueTrial' => _('Continue Trial'),
'serverInfoToggle' => _('Toggle server info visibility'),
'youCanSafelyCloseThisWindow' => _('You can safely close this window'),
'automaticallyClosingIn' => sprintf(_('Auto closing in %s'), '{0}'),
'byeBye' => _('bye bye 👋'),
'browserWillSelfDestructIn' => sprintf(_('Browser will self destruct in %s'), '{0}'),
'closingPopUpMayLeadToErrors' => _('Closing this pop-up window while actions are being preformed may lead to unintended errors'),
'goBack' => _('Go Back'),
'shutDown' => _('Shut Down'),
'haveAccountSignIn' => _('Already have an account').'? '._('Sign In'),
'noAccountSignUp' => _('Do not have an account').'? '._('Sign Up'),
'willConnectYourServerToMyServers' => _('This will register your server with Connect <sup>BETA</sup>'),
'serverInfo' => [
'flash' => _('Flash'),
'product' => _('Product'),
'GUID' => _('GUID'),
'name' => _('Name'),
'ip' => _('IP'),
],
'forms' => [
'displayName' => _('Display Name'),
'emailAddress' => _('Email Address'),
'displayNameOrEmailAddress' => _('Display Name or Email Address'),
'displayNameRootMessage' => _('Use your Unraid.net credentials, not your local server credentials'),
'honeyPotCopy' => _('If you fill this field out then your email will not be sent'),
'fieldRequired' => _('This field is required'),
'submit' => _('Submit'),
'submitting' => _('Submitting'),
'notValid' => _('Form not valid'),
'cancel' => _('Cancel'),
'confirm' => _('Confirm'),
'createMyAccount' => _('Create My Account'),
'subject' => _('Subject'),
'password' => _('Password'),
'togglePasswordVisibility' => _('Toggle Password Visibility'),
'message' => _('Message'),
'confirmPassword' => _('Confirm Password'),
'passwordMustMatch' => _('Password confirmation must match'),
'passwordMinimum' => _('8 or more characters'),
'comments' => _('comments'),
'newsletterCopy' => _('Sign me up for the monthly Unraid newsletter').': '._('a digest of recent blog posts, community videos, popular forum threads, product announcements, and more'),
'terms' => [
'iAgree' => _('I agree to the'),
'text' => _('Terms of Use'),
],
],
'routes' => [
'extendTrial' => [
'heading' => [
'loading' => _('Extending Trial'),
'error' => _('Trial Extension Failed'),
],
'message' => _('Not ready to purchase?').'<br>'._('Receive an additional 15 days for your trial').'.',
],
'forgotPassword' => [
'heading' => _('Forgot Password'),
'subheading' => _("After resetting your password come back to the Registration Wizard pop-up window to Sign In and complete your server's registration"),
'resetPasswordNow' => _('Reset Password Now'),
'backToSignIn' => _('Back to Sign In'),
],
'signIn' => [
'heading' => [
'signIn' => _('Unraid.net Sign In'),
'recover' => _('Unraid.net Sign In to Recover Key'),
'replace' => _('Unraid.net Sign In to Replace Key'),
],
'form' => [
'replacementConditions' => [
'name' => _('Acknowledge Replacement Conditions'),
'label' => _('I acknowledge that replacing a license key results in permanently blacklisting the previous USB Flash GUID'),
],
'label' => [
'password' => [
'replace' => _('Unraid.net account password'),
],
],
],
],
'signUp' => [
'heading' => _('Create Unraid.net Account'),
],
'signOut' => [
'heading' => _('Unraid.net Sign Out'),
'warnings' => [
'remoteAccessDisabled' => _('Remote access will be disabled'),
'remoteAccessInaccessible' => sprintf(_('You will no longer have access to this server using <abbr title="%s" class="italic">this url</abbr>'), '{0}'),
'disablingFlashBackup' => _('Automated flash backups will be disabled until you sign in again'),
'downloadFlashBackup' => _('Download latest backup from Connect Dashboard before signing out'),
],
],
'success' => [
'heading' => [
'username' => sprintf(_('Hi %s'), '{0}'),
'default' => _('Success'),
],
'subheading' => [
'extention' => _('Your trial will expire in 15 days'),
'newTrial' => _('Your trial will expire in 30 days'),
],
'signIn' => [
'tileTitle' => [
'actionFail' => sprintf(_('%s was not signed in to your Unraid.net account'), '{0}'),
'actionSuccess' => sprintf(_('%s is signed in to your Unraid.net account'), '{0}'),
'loading' => sprintf(_('Signing in %s to Unraid.net account'), '{0}'),
],
],
'signOut' => [
'tileTitle' => [
'actionFail' => sprintf(_('%s was not signed out of your Unraid.net account'), '{0}'),
'actionSuccess' => sprintf(_('%s was signed out of your Unraid.net account'), '{0}'),
'loading' => sprintf(_('Signing out %s from Unraid.net account'), '{0}'),
],
],
'keys' => [
'trial' => _('Trial'),
'basic' => _('Basic'),
'plus' => _('Plus'),
'pro' => _('Pro'),
],
'extended' => sprintf(_('%s Key Extended'), '{0}'),
'recovered' => sprintf(_('%s Key Recovered'), '{0}'),
'replaced' => sprintf(_('%s Key Replaced'), '{0}'),
'created' => sprintf(_('%s Key Created'), '{0}'),
'install' => [
'loading' => sprintf(_('Installing %s Key'), '{0}'),
'error' => sprintf(_('%s Key Install Error'), '{0}'),
'success' => sprintf(_('Installed %s Key'), '{0}'),
'manualInstructions' => _('To manually install the key paste the key file url into the Key file URL field on the webGUI Tools > Registration page and then click Install Key') . '.',
'copyFail' => _('Unable to copy'),
'copySuccess' => _('Copied key url') . '!',
'copyButton' => _('Copy Key URL'),
'copyBeforeClose' => _('Please copy the Key URL before closing this window'),
],
'timeout' => sprintf(_('Communication with %s has timed out'), '{0}'),
'loading1' => _('Please keep this window open'),
'loading2' => _('Still working our magic'),
'countdown' => [
'success' => [
'prefix' => sprintf(_('Auto closing in %s'), '{0}'),
'text' => _('You can safely close this window'),
],
'error' => [
'prefix' => sprintf(_('Auto redirecting in %s'), '{0}'),
'text' => _('Back to Registration Home'),
'complete' => _('Back in a flash ⚡️'),
],
],
],
'troubleshoot' => [
'heading' => [
'default' => _('Troubleshoot'),
'success' => _('Thank you for contacting Unraid'),
],
'subheading' => [
'default' => _("Forgot what Unraid.net account you used").'? '._("Have a USB flash device that already has an account associated with it").'? '._("Just give us the details about what happened and we'll do our best to get you up and running again").'.',
'success' => _('We have received your e-mail and will respond in the order it was received').'. '._('While we strive to respond to all requests as quickly as possible please allow for up to 3 business days for a response').'.',
],
'relevantServerData' => _('Your USB Flash GUID and other relevant server data will also be sent'),
],
'verifyEmail' => [
'heading' => _('Verify Email'),
'subheading' => sprintf(_('We have sent a verifcation email to %s'), '{0}'),
'form' => [
'verificationCode' => _('verification code'),
'verifyCode' => _('Paste or Enter code'),
],
'noCode' => _("Didn't get code?"),
],
'verifyEmailResend' => [
'heading' => _('Resend Email Verification Code'),
'goBack' => _("Have the code now? Go Back"),
'resend' => _("Resend Code"),
],
'whatIsMyServers' => [
'heading' => _('What is Unraid.net?'),
'subheading' => _('Expand your servers capabilities'),
'copy' => _('With an Unraid.net account you can start using Connect (beta) which gives you access to the following features:'),
'features' => [
"dynamicRemoteAccess" => [
'heading' => _('Dynamic Remote Access'),
'copy' => _('Toggle on/off server accessibility with dynamic remote access').'. '._('Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds').'.',
],
"manageWithinConnect" => [
'heading' => _('Manage Your Server Within Connect'),
'copy' => _('Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI').'. '._('Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window').'.',
],
"deepLinking" => [
'heading' => _('Deep Linking'),
'copy' => _('The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections').'.',
],
"onlineFlashBackup" => [
'heading' => _('Online Flash Backup'),
'copy' => _('Never ever be left without a backup of your config').'. '._('If you need to change flash drives, generate a backup from Connect and be up and running in minutes').'.',
],
"realTimeMonitoring" => [
'heading' => _('Real-time Monitoring'),
'copy' => _("Get an overview of your server's state, storage space, apps and VMs status, and more").'.',
],
"customizableDashboardTitles" => [
'heading' => _('Customizable Dashboard Tiles'),
'copy' => _("Set custom server tiles how you like and automatically display your server's banner image on your Connect Dashboard").'.',
],
"licenseManagement" => [
'heading' => _('License Management'),
'copy' => _('Manage your license keys at any time via the My Keys section').'.',
],
'plusMore' => [
'heading' => _('Plus more on the way'),
'copy' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin').'. '._('Get started by installing the plugin') . '.',
],
],
],
'replaceKey' => [
'subheading' => [
'registered' => 'A record of your replacement will be sent to your Unraid.net account email address',
'notRegistered' => 'A record of your replacement will be sent to this email',
],
],
'notFound' => [
'subheading' => _('Page Not Found'),
],
'notAllowed' => [
'subheading' => _('Page Not Allowed'),
],
],
],
'wanIpCheck' => [
'checking' => _('Checking Wan IPs'),
'match' => sprintf(_('Remark: your WAN IPv4 is **%s**'), '{0}'),
'mismatch' => sprintf(_("Remark: Unraid's WAN IPv4 **%1s** does not match your client's WAN IPv4 **%2s**"), '{0}', '{1}').'. '._('This may indicate a complex network that will not work with this Remote Access solution').'. '._('Ignore this message if you are currently connected via Remote Access or VPN').'.',
'resolveError' => _('DNS issue, unable to resolve wanip4.unraid.net'),
],
'upcTrigger' => [
'upgrade' => _('To support more storage devices as your server grows click the *Open Dropdown* button').'.',
'default' => _('Key management is done via the dropdown in the top right of the webGUI on every page').'.',
'open' => _('Open Dropdown'),
],
'yargYePirate' => _('Oh no! Are you pirating Unraid OS?<br>Are you ready to buy a real license?'),
'keyFileNotValid' => _('Key file not valid'),
'installFailed' => [
'heading' => _('Connect plugin install failed'),
'message' => _('The Connect plugin install is incomplete').'. '._('Please uninstall and reinstall the Connect plugin').'. '._('Be sure to let the install complete before you close the window').'.',
],
"downloadUnraidApiLogs" => _('Download unraid-api Logs'),
"download" => _('Download'),
"pleaseWait" => _('Please wait…')
],
];
// note: $myservers variable defined in myservers1.php, by parsing myservers.cfg
$configErrorEnum = [ // used to map $var['configValid'] value to mimic unraid-api's `configError` ENUM
"error" => 'UNKNOWN_ERROR',
"invalid" => 'INVALID',
"nokeyserver" => 'NO_KEY_SERVER',
"withdrawn" => 'WITHDRAWN',
];
$nginx = parse_ini_file('/var/local/emhttp/nginx.ini');
$plgInstalled = '';
if (!file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net') && !file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) {
$plgInstalled = ''; // base OS only, plugin not installed • show ad for plugin
} else {
// plugin is installed but if the unraid-api file doesn't fully install it's a failed install
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) $plgInstalled = 'dynamix.unraid.net.plg';
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) $plgInstalled = 'dynamix.unraid.net.staging.plg';
// plugin install failed • append failure detected so we can show warning about failed install via UPC
if (!file_exists('/usr/local/sbin/unraid-api')) $plgInstalled = $plgInstalled . '_installFailed';
}
// read flashbackup ini file
$flashbackup_ini = '/var/local/emhttp/flashbackup.ini';
$flashbackup_status = (file_exists($flashbackup_ini)) ? @parse_ini_file($flashbackup_ini) : [];
$serverstate = [ // feeds server vars to Vuex store in a slightly different array than state.php
"avatar" => (!empty($myservers['remote']['avatar']) && $plgInstalled) ? $myservers['remote']['avatar'] : '',
"config" => [
'valid' => $var['configValid'] === 'yes',
'error' => $var['configValid'] !== 'yes'
? (array_key_exists($var['configValid'], $configErrorEnum) ? $configErrorEnum[$var['configValid']] : 'UNKNOWN_ERROR')
: null,
],
"deviceCount" => $var['deviceCount'],
"email" => $myservers['remote']['email'] ?? '',
"extraOrigins" => explode(',', $myservers['api']['extraOrigins']??''),
"flashproduct" => $var['flashProduct'],
"flashvendor" => $var['flashVendor'],
"flashBackupActivated" => empty($flashbackup_status['activated']) ? '' : 'true',
"guid" => $var['flashGUID'],
"hasRemoteApikey" => !empty($myservers['remote']['apikey']),
"internalip" => ipaddr(),
"internalport" => $_SERVER['SERVER_PORT'],
"keyfile" => empty($var['regFILE'])? "" : str_replace(['+','/','='], ['-','_',''], trim(base64_encode(@file_get_contents($var['regFILE'])))),
"osVersion" => $var['version'],
"plgVersion" => $plgversion = file_exists('/var/log/plugins/dynamix.unraid.net.plg')
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
: ( file_exists('/var/log/plugins/dynamix.unraid.net.staging.plg')
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
: 'base-'.$var['version'] ),
"plgInstalled" => $plgInstalled,
"protocol" => $_SERVER['REQUEST_SCHEME'],
"reggen" => (int)$var['regGen'],
"regGuid" => $var['regGUID'],
"registered" => (!empty($myservers['remote']['username']) && $plgInstalled),
"servername" => $var['NAME'],
"site" => $_SERVER['REQUEST_SCHEME']."://".$_SERVER['HTTP_HOST'],
"state" => strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']),
"ts" => time(),
"username" => (!empty($myservers['remote']['username']) && $plgInstalled) ? $myservers['remote']['username'] : '',
"wanFQDN" => $nginx['NGINX_WANFQDN'] ?? '',
];
/** @TODO - prop refactor needed. The issue is because the prop names share the same name as the vuex store variables
* if we remove the props and deployed a UPC that doesn't rely on props anymore uses that don't have an updated version
* of this file will have a non-working UPC.
* apikey
* apiVersion
* csrf
* expiretime
* hideMyServers
* plgPath
* regWizTime
* sendCrashInfo
* serverdesc
* servermodel
* serverupdate
* uptime
*/
$serverState = new ServerState();
$wCTranslations = new WebComponentTranslations();
?>
<unraid-user-profile
apikey="<?=$myservers['upc']['apikey'] ?? ''?>"
api-version="<?=$myservers['api']['version'] ?? ''?>"
banner="<?=$display['banner'] ?? ''?>"
bgcolor="<?=($backgnd) ? '#'.$backgnd : ''?>"
csrf="<?=$var['csrf_token']?>"
displaydesc="<?=($display['headerdescription']??''!='no') ? 'true' : ''?>"
expiretime="<?=1000*($var['regTy']=='Trial'||strstr($var['regTy'],'expired')?$var['regTm2']:0)?>"
hide-my-servers="<?=$plgInstalled ? '' : 'yes' ?>"
locale="<?=($_SESSION['locale']) ? $_SESSION['locale'] : 'en_US'?>"
locale-messages="<?=rawurlencode(json_encode($upc_translations, JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE))?>"
metacolor="<?=($display['headermetacolor']??'') ? '#'.$display['headermetacolor'] : ''?>"
plg-path="dynamix.my.servers"
reg-wiz-time="<?=$myservers['remote']['regWizTime'] ?? ''?>"
serverdesc="<?=$var['COMMENT']?>"
servermodel="<?=$var['SYS_MODEL']?>"
serverstate="<?=rawurlencode(json_encode($serverstate, JSON_UNESCAPED_SLASHES))?>"
show-banner-gradient="<?=$display['showBannerGradient'] ?? 'yes'?>"
textcolor="<?=($header) ? '#'.$header : ''?>"
theme="<?=$display['theme']?>"
uptime="<?=1000*(time() - round(strtok(exec("cat /proc/uptime"),' ')))?>"
></unraid-user-profile>
<!-- /myservers2 -->
<script>
window.LOCALE_DATA = '<?= $wCTranslations->getTranslationsJson(true) ?>';
/**
* So we're not needing to modify DefaultLayout with an additional include, we'll add the Modals web component to the bottom of the body.
*/
const i18nHostWebComponent = 'unraid-i18n-host';
const modalsWebComponent = 'unraid-modals';
if (!document.getElementsByTagName(modalsWebComponent).length) {
const $body = document.getElementsByTagName('body')[0];
const $i18nHost = document.createElement(i18nHostWebComponent);
const $modals = document.createElement(modalsWebComponent);
$body.appendChild($i18nHost);
$i18nHost.appendChild($modals);
}
</script>
<unraid-i18n-host>
<unraid-user-profile server="<?= $serverState->getServerStateJsonForHtmlAttr() ?>"></unraid-user-profile>
</unraid-i18n-host>

View File

@@ -0,0 +1,105 @@
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* RebootDetails class is responsible for detecting the type and version of a system reboot required in the context of an unRAID server.
*
* Usage:
* ```
* $rebootDetails = new RebootDetails();
* $rebootType = $rebootDetails->getRebootType();
* ```
*/
class RebootDetails
{
/**
* @var string $rebootType Stores the type of reboot required, which can be 'update', 'downgrade', or 'thirdPartyDriversDownloading'.
*/
private $rebootType = '';
/**
* Constructs a new RebootDetails object and automatically detects the reboot type during initialization.
*/
public function __construct()
{
$this->detectRebootType();
}
/**
* Detects the type of reboot required based on the contents of the unRAID server's README.md file.
* Sets the $rebootType property accordingly.
*/
private function detectRebootType()
{
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
$rebootReadme = @file_get_contents("$docroot/plugins/unRAIDServer/README.md", false, null, 0, 20) ?: '';
$rebootDetected = preg_match("/^\*\*(REBOOT REQUIRED|DOWNGRADE)/", $rebootReadme);
$rebootForDowngrade = $rebootDetected && strpos($rebootReadme, 'DOWNGRADE') !== false;
$rebootForUpdate = $rebootDetected && strpos($rebootReadme, 'REBOOT REQUIRED') !== false;
$this->rebootType = $rebootForDowngrade ? 'downgrade' : ($rebootForUpdate ? 'update' : '');
// Detect if third-party drivers were part of the update process
$processWaitingThirdPartyDrivers = "inotifywait -q /boot/changes.txt -e move_self,delete_self";
// Run the ps command to list processes and check if the process is running
$ps_command = "ps aux | grep -E \"$processWaitingThirdPartyDrivers\" | grep -v \"grep -E\"";
$output = shell_exec($ps_command) ?? '';
if ($this->rebootType != '' && strpos($output, $processWaitingThirdPartyDrivers) !== false) {
$this->rebootType = 'thirdPartyDriversDownloading';
}
}
/**
* Gets the type of reboot required, which can be 'update', 'downgrade', or 'thirdPartyDriversDownloading'.
*
* @return string The type of reboot required.
*/
public function getRebootType()
{
return $this->rebootType;
}
/**
* Detects and retrieves the version information related to the system reboot based on the contents of the '/boot/changes.txt' file.
*
* @return string The system version information or 'Not found' if not found, or 'File not found' if the file is not present.
*/
public function getRebootVersion()
{
$file_path = '/boot/changes.txt';
// Check if the file exists
if (file_exists($file_path)) {
// Open the file for reading
$file = fopen($file_path, 'r');
// Read the file line by line until we find a line that starts with '# Version'
while (($line = fgets($file)) !== false) {
if (strpos($line, '# Version') === 0) {
// Use a regular expression to extract the full version string
if (preg_match('/# Version\s+(\S+)/', $line, $matches)) {
$fullVersion = $matches[1];
return $fullVersion;
} else {
return 'Not found';
}
break;
}
}
// Close the file
fclose($file);
} else {
return 'File not found';
}
}
}

View File

@@ -1,6 +1,5 @@
<?PHP
<?php
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -9,65 +8,330 @@
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
/**
* @todo refactor globals currently if you try to use $GLOBALS the class will break.
*/
$webguiGlobals = $GLOBALS;
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Helpers.php";
/* add translations */
$_SERVER['REQUEST_URI'] = '';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
/**
* ServerState class encapsulates server-related information and settings.
*
* Usage:
* ```
* require_once "$docroot/plugins/dynamix.my.servers/include/state.php";
* $serverStateClass = new ServerState();
*
* $serverStateClass->getServerState();
* or
* $serverStateClass->getServerStateJson();
* ```
*/
class ServerState
{
protected $webguiGlobals;
$var = (array)parse_ini_file('state/var.ini');
$license_state = strtoupper(empty($var['regCheck']) ? $var['regTy'] : $var['regCheck']);
$key_contents = empty($var['regFILE'])? "" : str_replace(['+','/','='], ['-','_',''], trim(base64_encode(@file_get_contents($var['regFILE']))));
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
$myservers = file_exists($myservers_flash_cfg_path) ? @parse_ini_file($myservers_flash_cfg_path,true) : [];
private $var;
private $apiKey = '';
private $apiVersion = '';
private $avatar = '';
private $email = '';
private $extraOrigins = [];
private $flashBackupActivated = '';
private $hasRemoteApikey = false;
private $registeredTime = '';
private $username = '';
private $connectPluginInstalled = '';
private $connectPluginVersion;
private $configErrorEnum = [
"error" => 'UNKNOWN_ERROR',
"ineligible" => 'INELIGIBLE',
"invalid" => 'INVALID',
"nokeyserver" => 'NO_KEY_SERVER',
"withdrawn" => 'WITHDRAWN',
];
private $osVersion;
private $osVersionBranch;
private $rebootDetails;
private $caseModel = '';
private $keyfileBase64UrlSafe = '';
private $updateOsCheck;
private $updateOsNotificationsEnabled = false;
private $updateOsResponse;
private $updateOsIgnoredReleases = [];
$configErrorEnum = [ // used to map $var['configValid'] value to mimic unraid-api's `configError` ENUM
"error" => 'UNKNOWN_ERROR',
"invalid" => 'INVALID',
"nokeyserver" => 'NO_KEY_SERVER',
"withdrawn" => 'WITHDRAWN',
];
public $myServersFlashCfg = [];
public $myServersMemoryCfg = [];
public $host = 'unknown';
public $combinedKnownOrigins = [];
public $nginxCfg = [];
public $flashbackupStatus = [];
public $registered = false;
public $myServersMiniGraphConnected = false;
public $keyfileBase64 = '';
$arr = [];
if (empty($myservers['remote']['username'])) {
$arr['registered'] = 0;
$arr['username'] = '';
$arr['avatar'] = '';
} else {
$arr['registered'] = 1;
$arr['username'] = $myservers['remote']['username'];
$arr['avatar'] = $myservers['remote']['avatar']??'';
/**
* Constructor to initialize class properties and gather server information.
*/
public function __construct()
{
/**
* @note necessary evil until full webgui is class based.
* @see - getWebguiGlobal() for usage
* */
global $webguiGlobals;
$this->webguiGlobals =& $webguiGlobals;
// echo "<pre>" . json_encode($this->webguiGlobals, JSON_PRETTY_PRINT) . "</pre>";
$this->var = (array)parse_ini_file('state/var.ini');
$this->nginxCfg = @parse_ini_file('/var/local/emhttp/nginx.ini') ?? [];
$this->osVersion = $this->var['version'];
$this->osVersionBranch = trim(@exec('plugin category /var/log/plugins/unRAIDServer.plg') ?? 'stable');
$caseModelFile = '/boot/config/plugins/dynamix/case-model.cfg';
$this->caseModel = file_exists($caseModelFile) ? file_get_contents($caseModelFile) : '';
$this->rebootDetails = new RebootDetails();
$this->keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
if ($this->keyfileBase64 !== false) {
$this->keyfileBase64 = @base64_encode($this->keyfileBase64);
$this->keyfileBase64UrlSafe = str_replace(['+', '/', '='], ['-', '_', ''], trim($this->keyfileBase64));
}
$this->updateOsCheck = new UnraidOsCheck();
$this->updateOsIgnoredReleases = $this->updateOsCheck->getIgnoredReleases();
$this->updateOsNotificationsEnabled = !empty(@$this->getWebguiGlobal('notify', 'unraidos'));
$this->updateOsResponse = $this->updateOsCheck->getUnraidOSCheckResult();
$this->setConnectValues();
}
/**
* Retrieve the value of a webgui global setting.
*/
public function getWebguiGlobal(string $key, string $subkey = null) {
if (!$subkey) {
return _var($this->webguiGlobals, $key, '');
}
$keyArray = _var($this->webguiGlobals, $key, []);
return _var($keyArray, $subkey, '');
}
private function setConnectValues() {
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net')) {
$this->connectPluginInstalled = 'dynamix.unraid.net.plg';
}
if (file_exists('/var/lib/pkgtools/packages/dynamix.unraid.net.staging')) {
$this->connectPluginInstalled = 'dynamix.unraid.net.staging.plg';
}
if ($this->connectPluginInstalled && !file_exists('/usr/local/sbin/unraid-api')) {
$this->connectPluginInstalled .= '_installFailed';
}
// exit early if the plugin is not installed
if (!$this->connectPluginInstalled) {
return;
}
$this->connectPluginVersion = file_exists('/var/log/plugins/dynamix.unraid.net.plg')
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
: (file_exists('/var/log/plugins/dynamix.unraid.net.staging.plg')
? trim(@exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
: 'base-' . $this->var['version']);
$this->getMyServersCfgValues();
$this->getConnectKnownOrigins();
$this->getFlashBackupStatus();
}
private function getFlashBackupStatus() {
$flashbackupCfg = '/var/local/emhttp/flashbackup.ini';
$this->flashbackupStatus = (file_exists($flashbackupCfg)) ? @parse_ini_file($flashbackupCfg) : [];
$this->flashBackupActivated = empty($this->flashbackupStatus['activated']) ? '' : 'true';
}
private function getMyServersCfgValues() {
/**
* @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg…
* - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
* - $mystatus = (file_exists($myservers_memory_cfg_path)) ? @parse_ini_file($myservers_memory_cfg_path) : [];
*/
$flashCfgPath = '/boot/config/plugins/dynamix.my.servers/myservers.cfg';
$this->myServersFlashCfg = file_exists($flashCfgPath) ? @parse_ini_file($flashCfgPath, true) : [];
// ensure some vars are defined here so we don't have to test them later
if (empty($this->myServersFlashCfg['remote']['apikey'])) {
$this->myServersFlashCfg['remote']['apikey'] = "";
}
if (empty($this->myServersFlashCfg['remote']['wanaccess'])) {
$this->myServersFlashCfg['remote']['wanaccess'] = "no";
}
if (empty($this->myServersFlashCfg['remote']['wanport'])) {
$this->myServersFlashCfg['remote']['wanport'] = 33443;
}
if (empty($this->myServersFlashCfg['remote']['upnpEnabled'])) {
$this->myServersFlashCfg['remote']['upnpEnabled'] = "no";
}
if (empty($this->myServersFlashCfg['remote']['dynamicRemoteAccessType'])) {
$this->myServersFlashCfg['remote']['dynamicRemoteAccessType'] = "DISABLED";
}
$this->apiKey = $this->myServersFlashCfg['upc']['apikey'] ?? '';
$this->apiVersion = $this->myServersFlashCfg['api']['version'] ?? '';
$this->avatar = (!empty($this->myServersFlashCfg['remote']['avatar']) && $this->connectPluginInstalled) ? $this->myServersFlashCfg['remote']['avatar'] : '';
$this->email = $this->myServersFlashCfg['remote']['email'] ?? '';
$this->hasRemoteApikey = !empty($this->myServersFlashCfg['remote']['apikey']);
$this->registered = !empty($this->myServersFlashCfg['remote']['apikey']) && $this->connectPluginInstalled;
$this->registeredTime = $this->myServersFlashCfg['remote']['regWizTime'] ?? '';
$this->username = $this->myServersFlashCfg['remote']['username'] ?? '';
}
private function getConnectKnownOrigins() {
/**
* Allowed origins warning displayed when the current webGUI URL is NOT included in the known lists of allowed origins.
* Include localhost in the test, but only display HTTP(S) URLs that do not include localhost.
*/
$this->host = $_SERVER['HTTP_HOST'] ?? "unknown";
$memoryCfgPath = '/var/local/emhttp/myservers.cfg';
$this->myServersMemoryCfg = (file_exists($memoryCfgPath)) ? @parse_ini_file($memoryCfgPath) : [];
$this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph']??'') === 'CONNECTED');
$allowedOrigins = $this->myServersMemoryCfg['allowedOrigins'] ?? "";
$extraOrigins = $this->myServersFlashCfg['api']['extraOrigins'] ?? "";
$combinedOrigins = $allowedOrigins . "," . $extraOrigins; // combine the two strings for easier searching
$combinedOrigins = str_replace(" ", "", $combinedOrigins); // replace any spaces with nothing
$hostNotKnown = stripos($combinedOrigins, $this->host) === false; // check if the current host is in the combined list of origins
if ($extraOrigins) {
$this->extraOrigins = explode(",", $extraOrigins);
}
if ($hostNotKnown) {
$this->combinedKnownOrigins = explode(",", $combinedOrigins);
if ($this->combinedKnownOrigins) {
foreach($this->combinedKnownOrigins as $key => $origin) {
if ( (strpos($origin, "http") === false) || (strpos($origin, "localhost") !== false) ) {
// clean up $this->combinedKnownOrigins, only display warning if origins still remain to display
unset($this->combinedKnownOrigins[$key]);
}
}
// for some reason the unset creates an associative array, so reindex the array with just the values. Otherwise we get an object passed to the UPC JS instead of an array.
if ($this->combinedKnownOrigins) {
$this->combinedKnownOrigins = array_values($this->combinedKnownOrigins);
}
}
}
}
/**
* Retrieve the server information as an associative array
*
* @return array An array containing server information.
*/
public function getServerState()
{
$serverState = [
"apiKey" => $this->apiKey,
"apiVersion" => $this->apiVersion,
"avatar" => $this->avatar,
"caseModel" => $this->caseModel,
"config" => [
'valid' => ($this->var['configValid'] === 'yes'),
'error' => isset($this->configErrorEnum[$this->var['configValid']]) ? $this->configErrorEnum[$this->var['configValid']] : null,
],
"connectPluginInstalled" => $this->connectPluginInstalled,
"connectPluginVersion" => $this->connectPluginVersion,
"csrf" => $this->var['csrf_token'],
"dateTimeFormat" => [
"date" => @$this->getWebguiGlobal('display', 'date') ?? '',
"time" => @$this->getWebguiGlobal('display', 'time') ?? '',
],
"description" => $this->var['COMMENT'] ? htmlspecialchars($this->var['COMMENT'], ENT_HTML5, 'UTF-8') : '',
"deviceCount" => $this->var['deviceCount'],
"email" => $this->email,
"expireTime" => 1000 * (($this->var['regTy'] === 'Trial' || strstr($this->var['regTy'], 'expired')) ? $this->var['regTm2'] : 0),
"extraOrigins" => $this->extraOrigins,
"flashProduct" => $this->var['flashProduct'],
"flashVendor" => $this->var['flashVendor'],
"flashBackupActivated" => $this->flashBackupActivated,
"guid" => $this->var['flashGUID'],
"hasRemoteApikey" => $this->hasRemoteApikey,
"internalPort" => _var($_SERVER, 'SERVER_PORT'),
"keyfile" => $this->keyfileBase64UrlSafe,
"lanIp" => ipaddr(),
"locale" => (!empty($_SESSION) && $_SESSION['locale']) ? $_SESSION['locale'] : 'en_US',
"model" => $this->var['SYS_MODEL'] ? htmlspecialchars($this->var['SYS_MODEL'], ENT_HTML5, 'UTF-8') : '',
"name" => htmlspecialchars($this->var['NAME'], ENT_HTML5, 'UTF-8'),
"osVersion" => $this->osVersion,
"osVersionBranch" => $this->osVersionBranch,
"protocol" => _var($_SERVER, 'REQUEST_SCHEME'),
"rebootType" => $this->rebootDetails->getRebootType(),
"regDevs" => @(int)$this->var['regDevs'] ?? 0,
"regGen" => @(int)$this->var['regGen'],
"regGuid" => @$this->var['regGUID'] ?? '',
"regTo" => @htmlspecialchars($this->var['regTo'], ENT_HTML5, 'UTF-8') ?? '',
"regTm" => $this->var['regTm'] ? @$this->var['regTm'] * 1000 : '', // JS expects milliseconds
"regTy" => @$this->var['regTy'] ?? '',
"regExp" => $this->var['regExp'] ? @$this->var['regExp'] * 1000 : '', // JS expects milliseconds
"registered" => $this->registered,
"registeredTime" => $this->registeredTime,
"site" => _var($_SERVER, 'REQUEST_SCHEME') . "://" . _var($_SERVER, 'HTTP_HOST'),
"state" => strtoupper(empty($this->var['regCheck']) ? $this->var['regTy'] : $this->var['regCheck']),
"theme" => [
"banner" => !empty($this->getWebguiGlobal('display', 'banner')),
"bannerGradient" => $this->getWebguiGlobal('display', 'showBannerGradient') === 'yes' ?? false,
"bgColor" => ($this->getWebguiGlobal('display', 'background')) ? '#' . $this->getWebguiGlobal('display', 'background') : '',
"descriptionShow" => (!empty($this->getWebguiGlobal('display', 'headerdescription')) && $this->getWebguiGlobal('display', 'headerdescription') !== 'no'),
"metaColor" => ($this->getWebguiGlobal('display', 'headermetacolor') ?? '') ? '#' . $this->getWebguiGlobal('display', 'headermetacolor') : '',
"name" => $this->getWebguiGlobal('display', 'theme'),
"textColor" => ($this->getWebguiGlobal('display', 'header')) ? '#' . $this->getWebguiGlobal('display', 'header') : '',
],
"ts" => time(),
"uptime" => 1000 * (time() - round(strtok(exec("cat /proc/uptime"), ' '))),
"username" => $this->username,
"wanFQDN" => @$this->nginxCfg['NGINX_WANFQDN'] ?? '',
];
if ($this->combinedKnownOrigins) {
$serverState['combinedKnownOrigins'] = $this->combinedKnownOrigins;
}
if ($this->updateOsIgnoredReleases) {
$serverState['updateOsIgnoredReleases'] = $this->updateOsIgnoredReleases;
}
if ($this->updateOsNotificationsEnabled) {
$serverState['updateOsNotificationsEnabled'] = $this->updateOsNotificationsEnabled;
}
if ($this->updateOsResponse) {
$serverState['updateOsResponse'] = $this->updateOsResponse;
}
return $serverState;
}
/**
* Retrieve the server information as JSON
*
* @return string
*/
public function getServerStateJson() {
return json_encode($this->getServerState());
}
/**
* Retrieve the server information as JSON string with converted special characters to HTML entities
*
* @return string
*/
public function getServerStateJsonForHtmlAttr() {
$json = json_encode($this->getServerState());
return htmlspecialchars($json, ENT_QUOTES, 'UTF-8');
}
}
$arr['event'] = 'STATE';
$arr['ts'] = time();
$arr['deviceCount'] = $var['deviceCount'];
$arr['guid'] = $var['flashGUID'];
$arr['regGuid'] = $var['regGUID'];
$arr['state'] = $license_state;
$arr['keyfile'] = $key_contents;
$arr['reggen'] = $var['regGen'];
$arr['flashproduct'] = $var['flashProduct'];
$arr['flashvendor'] = $var['flashVendor'];
$arr['servername'] = $var['NAME'];
$arr['serverdesc'] = $var['COMMENT'];
$arr['internalip'] = $_SERVER['SERVER_ADDR'];
$arr['internalport'] = $_SERVER['SERVER_PORT'];
$arr['plgVersion'] = 'base-'.$var['version'];
$arr['protocol'] = $_SERVER['REQUEST_SCHEME'];
$arr['locale'] = $_SESSION['locale'] ?? 'en_US';
$arr['expiretime']=1000*($var['regTy']=='Trial'||strstr($var['regTy'],'expired')?$var['regTm2']:0);
$arr['uptime']=1000*(time() - round(strtok(exec("cat /proc/uptime"),' ')));
$arr['hasRemoteApikey'] = empty($myservers['remote']['apikey']) ? 0 : 1;
$arr['hideMyServers'] = (file_exists('/usr/local/sbin/unraid-api')) ? '' : 'yes';
$arr['config'] = [
'valid' => $var['configValid'] === 'yes',
'error' => $var['configValid'] !== 'yes'
? (array_key_exists($var['configValid'], $configErrorEnum) ? $configErrorEnum[$var['configValid']] : 'UNKNOWN_ERROR')
: null,
];
echo json_encode($arr);
?>

View File

@@ -0,0 +1,364 @@
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* Welcome to the Thunderdome. A place where you can get lost in a sea of translations.
*
* This file is used to generate the translations for the Vue3 based web components.
*
* These key value pairs are derived from web/locales/en_US.json.
* We use the en_US.json file as the source of truth for the translations.
* This file is then used to generate the translations for the web components and delivered to them via PHP as a JSON object in myservers2.php (my favorite file name).
* The web components then use the translations to display the appropriate text to the user.
*
* Workflow is as follows:
* 1. Create a new translation in en_US.json
* 2. Create a new translation in this file
* 3. Open unraid/lang-en_US and add the new translation to the appropriate file typically translations.txt.
* 3a. This is done so that the translation is available to the rest of the Unraid webgui.
* 3b. Unfortunately there are numerous "special characters" that aren't allowed in Unraid's translation keys as they're automatically stripped out.
* 3c. This means that we have to create a new translation key that is a "safe" version of the translation key used in the web components.
* 3d. Special characters that are not allowed are: ? { } | & ~ ! [ ] ( ) / : * ^ . " '
* 3e. There are likely more but I'm unable to find the documentation PDF - updated list of invalid characters above as mentioned in the language guide document.
*
* Usage example:
* ```
* $wCTranslations = new WebComponentTranslations();
* $wCTranslations->getTranslations();
* ```
*/
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Translations.php";
class WebComponentTranslations
{
private $translations = [];
public function __construct()
{
$this->initializeTranslations();
}
private function initializeTranslations()
{
$this->translations[$_SESSION['locale'] ?? 'en_US'] = [
'{0} {1} Key…' => sprintf(_('%1s %2s Key…'), '{0}', '{1}'),
'{0} devices' => sprintf(_('%s devices'), '{0}'),
'{0} out of {1} allowed devices upgrade your key to support more devices' => sprintf(_('%1s out of %2s allowed devices upgrade your key to support more devices'), '{0}', '{1}'),
'{0} out of {1} devices' => sprintf(_('%1s out of %2s devices'), '{0}', '{1}'),
'{0} Release Notes' => sprintf(_('%s Release Notes'), '{0}'),
'{0} Signed In Successfully' => sprintf(_('%s Signed In Successfully'), '{0}'),
'{0} Signed Out Successfully' => sprintf(_('%s Signed Out Successfully'), '{0}'),
'{0} Update Available' => sprintf(_('%s Update Available'), '{0}'),
'{1} Key {0} Successfully' => sprintf(_('%2s Key %1s Successfully'), '{0}', '{1}'),
'<p>It is not possible to use a Trial key with an existing Unraid OS installation.</p><p>You may purchase a license key corresponding to this USB Flash device to continue using this installation.</p>' => '<p>' . _('It is not possible to use a Trial key with an existing Unraid OS installation') . '</p><p>' . _('You may purchase a license key corresponding to this USB Flash device to continue using this installation.') . '</p>',
'<p>Please refresh the page to ensure you load your latest configuration</p>' => '<p>' . _('Please refresh the page to ensure you load your latest configuration') . '</p>',
'<p>Register for Connect by signing in to your Unraid.net account</p>' => '<p>' . _('Register for Connect by signing in to your Unraid.net account') . '</p>',
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key.</p><p>Your Unraid registration key is ineligible for replacement as it is blacklisted.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device or choose Purchase Key') . '</p><p>' . _('Your Unraid registration key is ineligible for replacement as it is blacklisted.') . '</p>',
'<p>The license key file does not correspond to the USB Flash boot device. Please copy the correct key file to the /config directory on your USB Flash boot device.</p><p>You may also attempt to Purchase or Replace your key.</p>' => '<p>' . _('The license key file does not correspond to the USB Flash boot device.') . ' ' . _('Please copy the correct key file to the /config directory on your USB Flash boot device') . '</p><p>' . _('You may also attempt to Purchase or Replace your key.') . '</p>',
'<p>There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device. Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device.</p><p>Alternately you may purchase a license key for this USB flash device.</p><p>If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.</p>' => '<p>' . _('There are multiple license key files present on your USB flash device and none of them correspond to the USB Flash boot device.') . ' ' . _('Please remove all key files, except the one you want to replace, from the /config directory on your USB Flash boot device') . '</p><p>' . _('Alternately you may purchase a license key for this USB flash device') . '</p><p>' . _('If you want to replace one of your license keys with a new key bound to this USB Flash device, please first remove all other key files first.') . '</p>',
'<p>There is a physical problem accessing your USB Flash boot device</p>' => '<p>' . _('There is a physical problem accessing your USB Flash boot device') . '</p>',
'<p>There is a problem with your USB Flash device</p>' => '<p>' . _('There is a problem with your USB Flash device') . '</p>',
'<p>This USB Flash boot device has been blacklisted. This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.</p><p>A USB Flash device may also be blacklisted if we discover the serial number is not unique this is common with USB card readers.</p>' => '<p>' . _('This USB Flash boot device has been blacklisted.') . ' ' . _('This can occur as a result of transferring your license key to a replacement USB Flash device, and you are currently booted from your old USB Flash device.') . '</p><p>' . _('A USB Flash device may also be blacklisted if we discover the serial number is not unique this is common with USB card readers.') . '</p>',
'<p>This USB Flash device has an invalid GUID. Please try a different USB Flash device</p>' => '<p>' . _('This USB Flash device has an invalid GUID. Please try a different USB Flash device') . '</p>',
'<p>To continue using Unraid OS you may purchase a license key. Alternately, you may request a Trial extension.</p>' => '<p>' . _('To continue using Unraid OS you may purchase a license key.') . ' ' . _('Alternately, you may request a Trial extension.') . '</p>',
'<p>To support more storage devices as your server grows, click Upgrade Key.</p>' => '<p>' . _('To support more storage devices as your server grows, click Upgrade Key.') . '</p>',
'<p>You have used all your Trial extensions. To continue using Unraid OS you may purchase a license key.</p>' => '<p>' . _('You have used all your Trial extensions.') . ' ' . _('To continue using Unraid OS you may purchase a license key.') . '</p>',
'<p>Your <em>Trial</em> key includes all the functionality and device support of an <em>Unleashed</em> key.</p><p>After your <em>Trial</em> has reached expiration, your server <strong>still functions normally</strong> until the next time you Stop the array or reboot your server.</p><p>At that point you may either purchase a license key or request a <em>Trial</em> extension.</p>' => '<p>' . _('Your **Trial** key includes all the functionality and device support of an **Unleashed** key') . '</p><p>' . _('After your **Trial** has reached expiration, your server *still functions normally* until the next time you Stop the array or reboot your server') . '</p><p>' . _('At that point you may either purchase a license key or request a *Trial* extension.') . '</p>',
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>If you do not have a backup copy of your license key file you may attempt to recover your key.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
'<p>Your license key file is corrupted or missing. The key file should be located in the /config directory on your USB Flash boot device.</p><p>You may attempt to recover your key with your Unraid.net account.</p><p>If this was an expired Trial installation, you may purchase a license key.</p>' => '<p>' . _('Your license key file is corrupted or missing.') . ' ' . _('The key file should be located in the /config directory on your USB Flash boot device') . '</p><p>' . _('If you do not have a backup copy of your license key file you may attempt to recover your key with your Unraid.net account') . '</p><p>' . _('If this was an expired Trial installation, you may purchase a license key.') . '</p>',
'<p>Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key. A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.</p><p>Registration keys are bound to your USB Flash boot device serial number (GUID). Please use a high quality name brand device at least 1GB in size.</p><p>Note: USB memory card readers are generally not supported because most do not present unique serial numbers.</p><p><strong>Important:</strong></p><ul class="list-disc pl-16px"><li>Please make sure your server time is accurate to within 5 minutes</li><li>Please make sure there is a DNS server specified</li></ul>' => '<p>' . _('Your server will not be usable until you purchase a Registration key or install a free 30 day <em>Trial</em> key.') . ' ' . _('A <em>Trial</em> key provides all the functionality of an Unleashed Registration key.') . '</p><p>' . _('Registration keys are bound to your USB Flash boot device serial number (GUID).') . ' ' . _('Please use a high quality name brand device at least 1GB in size.') . '</p><p>' . _('Note: USB memory card readers are generally not supported because most do not present unique serial numbers.') . '</p><p>' . _('*Important:*') . '</p><ul class="list-disc pl-16px"><li>' . _('Please make sure your server time is accurate to within 5 minutes') . '</li><li>' . _('Please make sure there is a DNS server specified') . '</li>>' . '</ul>',
'<p>Your Trial key requires an internet connection.</p><p><a href="/Settings/NetworkSettings" class="underline">Please check Settings > Network</a></p>' => '<p>' . _('Your Trial key requires an internet connection') . '</p><p><a href="/Settings/NetworkSettings" class="underline">' . _('Please check Settings > Network') . '</a></p>',
'<p>Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.</p>' => '<p>' . _('Your Unraid registration key is ineligible for replacement as it has been replaced within the last 12 months.') . '</p>',
'A Trial key provides all the functionality of an Unleashed Registration key' => _('A Trial key provides all the functionality of an Unleashed Registration key'),
'Acklowledge that you have made a Flash Backup to enable this action' => _('Acklowledge that you have made a Flash Backup to enable this action'),
'ago' => _('ago'),
'All you need is an active internet connection, an Unraid.net account, and the Connect plugin. Get started by installing the plugin.' => _('All you need is an active internet connection, an Unraid.net account, and the Connect plugin.') . ' ' . _('Get started by installing the plugin.'),
'Attached Storage Devices' => _('Attached Storage Devices'),
'Backing up...this may take a few minutes' => _('Backing up...this may take a few minutes'),
'Basic' => _('Basic'),
'Begin downgrade to {0}' => sprintf(_('Begin downgrade to %s'), '{0}'),
'Beta' => _('Beta'),
'Blacklisted USB Flash GUID' => _('Blacklisted USB Flash GUID'),
'BLACKLISTED' => _('BLACKLISTED'),
'Calculating trial expiration…' => _('Calculating trial expiration…'),
'Callback redirect type not present or incorrect' => _('Callback redirect type not present or incorrect'),
'Cancel' => _('Cancel'),
'Cannot access your USB Flash boot device' => _('Cannot access your USB Flash boot device'),
'Cannot validate Unraid Trial key' => _('Cannot validate Unraid Trial key'),
'Check for OS Updates' => _('Check for OS Updates'),
'check for OS updates' => _('check for OS updates'),
'Check for Prereleases' => _('Check for Prereleases'),
'Checking WAN IPs…' => _('Checking WAN IPs…'),
'Checking...' => _('Checking...'),
'Checkout the Connect Documentation' => _('Checkout the Connect Documentation'),
'Click to close modal' => _('Click to close modal'),
'Click to Copy LAN IP {0}' => sprintf(_('Click to copy LAN IP %s'), '{0}'),
'Close Dropdown' => _('Close Dropdown'),
'Close Modal' => _('Close Modal'),
'Close' => _('Close'),
'Configure Connect Features' => _('Configure Connect Features'),
'Confirm and start update' => _('Confirm and start update'),
'Connected' => _('Connected'),
'Contact Support' => _('Contact Support'),
'Copied' => _('Copied'),
'Copy Key URL' => _('Copy Key URL'),
'Copy your Key URL: {0}' => sprintf(_('Copy your Key URL: %s'), '{0}'),
'Create Flash Backup' => _('Create Flash Backup'),
'Current Version {0}' => sprintf(_('Current Version %s'), '{0}'),
'Current Version: Unraid {0}' => sprintf(_('Current Version: Unraid %s'), '{0}'),
'Customizable Dashboard Tiles' => _('Customizable Dashboard Tiles'),
'day' => sprintf(_('%s day'), '{n}') . ' | ' . sprintf(_('%s days'), '{n}'),
'Deep Linking' => _('Deep Linking'),
'DNS issue, unable to resolve wanip4.unraid.net' => _('DNS issue, unable to resolve wanip4.unraid.net'),
'Downgrade Unraid OS to {0}' => sprintf(_('Downgrade Unraid OS to %s'), '{0}'),
'Downgrade Unraid OS' => _('Downgrade Unraid OS'),
'Downgrades are only recommended if you\'re unable to solve a critical issue.' => _('Downgrades are only recommended if you\'re unable to solve a critical issue.'),
'Download the Diagnostics zip then please open a bug report on our forums with a description of the issue along with your diagnostics.' => _('Download the Diagnostics zip then please open a bug report on our forums with a description of the issue along with your diagnostics.'),
'Download unraid-api Logs' => _('Download unraid-api Logs'),
'Dynamic Remote Access' => _('Dynamic Remote Access'),
'Enhance your experience with Unraid Connect' => _('Enhance your experience with Unraid Connect'),
'Enhance your Unraid experience with Connect' => _('Enhance your Unraid experience with Connect'),
'Enhance your Unraid experience' => _('Enhance your Unraid experience'),
'Error creatiing a trial key. Please try again later.' => _('Error creatiing a trial key. Please try again later.'),
'Error' => _('Error'),
'Expired {0}' => sprintf(_('Expired %s'), '{0}'),
'Expired' => _('Expired'),
'Expires at {0}' => sprintf(_('Expires at %s'), '{0}'),
'Expires in {0}' => sprintf(_('Expires in %s'), '{0}'),
'Extend Trial' => _('Extend Trial'),
'Extending your free trial by 15 days' => _('Extending your free trial by 15 days'),
'Extension Installed' => _('Extension Installed'),
'Failed to {0} {1} Key' => sprintf(_('Failed to %1s %2s Key'), '{0}', '{1}'),
'Failed to install key' => _('Failed to install key'),
'Failed to update Connect account configuration' => _('Failed to update Connect account configuration'),
'Fix Error' => _('Fix Error'),
'Flash Backup is not available. Navigate to {0}/Main/Settings/Flash to try again then come back to this page.' => sprintf(_('Flash Backup is not available. Navigate to %s/Main/Settings/Flash to try again then come back to this page.'), '{0}'),
'Flash GUID Error' => _('Flash GUID Error'),
'Flash GUID required to check replacement status' => _('Flash GUID required to check replacement status'),
'Flash GUID' => _('Flash GUID'),
'Flash Product' => _('Flash Product'),
'Flash Vendor' => _('Flash Vendor'),
'Get an overview of your server\'s state, storage space, apps and VMs status, and more.' => _('Get an overview of your server\'s state, storage space, apps and VMs status, and more.'),
'Get Started' => _('Get Started'),
'Go to Connect plugin settings' => _('Go to Connect plugin settings'),
'Go to Connect' => _('Go to Connect'),
'Go to Management Access Now' => _('Go to Management Access Now'),
'Go to Tools > Management Access to activate the Flash Backup feature and ensure your backup is up-to-date.' => _('Go to Tools > Management Access to activate the Flash Backup feature and ensure your backup is up-to-date.'),
'Go to Tools > Management Access to ensure your backup is up-to-date.' => _('Go to Tools > Management Access to ensure your backup is up-to-date.'),
'Go to Tools > Registration to fix' => _('Go to Tools > Registration to fix'),
'Go to Tools > Update' => _('Go to Tools > Update'),
'hour' => sprintf(_('%s hour'), '{n}') . ' | ' . sprintf(_('%s hours'), '{n}'),
'I have made a Flash Backup' => _('I have made a Flash Backup'),
'If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.' => _('If you are asked to supply logs, please open a support request on our Contact Page and reply to the email message you receive with your logs attached.'),
'Ignore this message if you are currently connected via Remote Access or VPN.' => _('Ignore this message if you are currently connected via Remote Access or VPN.'),
'In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue.' => _('In the rare event you need to downgrade we ask that you please provide us with Diagnostics so we can investigate your issue.'),
'Install Connect' => _('Install Connect'),
'Install Recovered' => _('Install Recovered'),
'Install Replaced' => _('Install Replaced'),
'Install' => _('Install'),
'Installed' => _('Installed'),
'Installing Extended Trial' => _('Installing Extended Trial'),
'Installing Extended' => _('Installing Extended'),
'Installing Recovered' => _('Installing Recovered'),
'Installing Replaced' => _('Installing Replaced'),
'Installing' => _('Installing'),
'Introducing Unraid Connect' => _('Introducing Unraid Connect'),
'Invalid API Key Format' => _('Invalid API Key Format'),
'Invalid API Key' => _('Invalid API Key'),
'Invalid installation' => _('Invalid installation'),
'Keyfile required to check replacement status' => _('Keyfile required to check replacement status'),
'LAN IP {0}' => sprintf(_('LAN IP %s'), '{0}'),
'LAN IP Copied' => _('LAN IP Copied'),
'LAN IP' => _('LAN IP'),
'Last checked: {0}' => sprintf(_('Last checked: %s'), '{0}'),
'Learn more about the error' => _('Learn more about the error'),
'Learn more and fix' => _('Learn more and fix'),
'Learn More' => _('Learn More'),
'Learn more' => _('Learn more'),
'Let\'s Unleash your Hardware!' => _('Let\'s Unleash your Hardware!'),
'License key actions' => _('License key actions'),
'License key type' => _('License key type'),
'License Management' => _('License Management'),
'Loading' => _('Loading'),
'Manage Unraid.net Account in new tab' => _('Manage Unraid.net Account in new tab'),
'Manage Unraid.net Account' => _('Manage Unraid.net Account'),
'Manage your license keys at any time via the My Keys section.' => _('Manage your license keys at any time via the My Keys section.'),
'Manage Your Server Within Connect' => _('Manage Your Server Within Connect'),
'minute' => sprintf(_('%s minute'), '{n}') . ' | ' . sprintf(_('%s minutes'), '{n}'),
'Missing key file' => _('Missing key file'),
'month' => sprintf(_('%s month'), '{n}') . ' | ' . sprintf(_('%s months'), '{n}'),
'Multiple License Keys Present' => _('Multiple License Keys Present'),
'Never ever be left without a backup of your config. If you need to change flash drives, generate a backup from Connect and be up and running in minutes.' => _('Never ever be left without a backup of your config.') . ' ' . _('If you need to change flash drives, generate a backup from Connect and be up and running in minutes.'),
'New Version: {0}' => sprintf(_('New Version: %s'), '{0}'),
'No downgrade available' => _('No downgrade available'),
'No Flash' => _('No Flash'),
'No Keyfile' => _('No Keyfile'),
'No thanks' => _('No thanks'),
'No USB flash configuration data' => _('No USB flash configuration data'),
'On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.' => _('On January 1st, 2023 SSL certificates for unraid.net were deprecated. You MUST provision a new SSL certificate to use our new myunraid.net domain. You can do this on the Settings > Management Access page.'),
'Online Flash Backup' => _('Online Flash Backup'),
'Open a bug report' => _('Open a bug report'),
'Open Dropdown' => _('Open Dropdown'),
'Opens Connect in new tab' => _('Opens Connect in new tab'),
'Original release date {0}' => sprintf(_('Original release date %s'), '{0}'),
'Performing actions' => _('Performing actions'),
'Please confirm the update details below' => _('Please confirm the update details below'),
'Please fix any errors and try again.' => _('Please fix any errors and try again.'),
'Please keep this window open while we perform some actions' => _('Please keep this window open while we perform some actions'),
'Please keep this window open' => _('Please keep this window open'),
'Please sign out then sign back in to refresh your API key.' => _('Please sign out then sign back in to refresh your API key.'),
'Please wait while the page reloads to install your trial key' => _('Please wait while the page reloads to install your trial key'),
'Plus more on the way' => _('Plus more on the way'),
'Plus' => _('Plus'),
'Pro' => _('Pro'),
'Purchase Key' => _('Purchase Key'),
'Purchase' => _('Purchase'),
'Ready to Install Key' => _('Ready to Install Key'),
'Ready to update Connect account configuration' => _('Ready to update Connect account configuration'),
'Real-time Monitoring' => _('Real-time Monitoring'),
'Reboot Now to Downgrade to {0}' => sprintf(_('Reboot Now to Downgrade to %s'), '{0}'),
'Reboot Now to Downgrade' => _('Reboot Now to Downgrade'),
'Reboot Now to Update to {0}' => sprintf(_('Reboot Now to Update to %s'), '{0}'),
'Reboot Now to Update' => _('Reboot Now to Update'),
'Reboot Required for Downgrade to {0}' => sprintf(_('Reboot Required for Downgrade to %s'), '{0}'),
'Reboot Required for Downgrade' => _('Reboot Required for Downgrade'),
'Reboot Required for Update to {0}' => sprintf(_('Reboot Required for Update to %s'), '{0}'),
'Reboot Required for Update' => _('Reboot Required for Update'),
'Rebooting will likely solve this.' => _('Rebooting will likely solve this.'),
'Receive the latest and greatest for Unraid OS. Whether it new features, security patches, or bug fixes keeping your server up-to-date ensures the best experience that Unraid has to offer.' => _('Receive the latest and greatest for Unraid OS.') . ' ' . _('Whether it new features, security patches, or bug fixes keeping your server up-to-date ensures the best experience that Unraid has to offer.'),
'Recover Key' => _('Recover Key'),
'Recovered' => _('Recovered'),
'Redeem Activation Code' => _('Redeem Activation Code'),
'Registered on' => _('Registered on'),
'Registered to' => _('Registered to'),
'Registration key / USB Flash GUID mismatch' => _('Registration key / USB Flash GUID mismatch'),
'Reload' => _('Reload'),
'Remark: Unraid\'s WAN IPv4 {0} does not match your client\'s WAN IPv4 {1}.' => sprintf(_('Remark: Unraid\'s WAN IPv4 %1s does not match your client\'s WAN IPv4 %2s.'), '{0}', '{1}'),
'Remark: your WAN IPv4 is {0}' => sprintf(_('Remark: your WAN IPv4 is %s'), '{0}'),
'Replace Key' => _('Replace Key'),
'Replaced' => _('Replaced'),
'Restarting unraid-api…' => _('Restarting unraid-api…'),
'second' => sprintf(_('%s second'), '{n}') . ' | ' . sprintf(_('%s seconds'), '{n}'),
'Server Up Since {0}' => sprintf(_('Server Up Since %s'), '{0}'),
'Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI. Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.' => _('Servers equipped with a myunraid.net certificate can be managed directly from within the Connect web UI.') . ' ' . _('Manage multiple servers from your phone, tablet, laptop, or PC in the same browser window.'),
'Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.' => _('Set custom server tiles how you like and automatically display your server\'s banner image on your Connect Dashboard.'),
'Settings' => _('Settings'),
'Sign In Failed' => _('Sign In Failed'),
'Sign In requires the local unraid-api to be running' => _('Sign In requires the local unraid-api to be running'),
'Sign In to utilize Unraid Connect' => _('Sign In to utilize Unraid Connect'),
'Sign In to your Unraid.net account to get started' => _('Sign In to your Unraid.net account to get started'),
'Sign In with Unraid.net Account' => _('Sign In with Unraid.net Account'),
'Sign Out Failed' => _('Sign Out Failed'),
'Sign Out of Unraid.net' => _('Sign Out of Unraid.net'),
'Sign Out requires the local unraid-api to be running' => _('Sign Out requires the local unraid-api to be running'),
'Signing in {0}…' => sprintf(_('Signing in %s…'), '{0}'),
'Signing In' => _('Signing In'),
'Signing out {0}…' => sprintf(_('Signing out %s…'), '{0}'),
'Signing Out' => _('Signing Out'),
'Something went wrong' => _('Something went wrong'),
'SSL certificates for unraid.net deprecated' => _('SSL certificates for unraid.net deprecated'),
'Stale Server' => _('Stale Server'),
'Stale' => _('Stale'),
'Start Free 30 Day Trial' => _('Start Free 30 Day Trial'),
'Starting your free 30 day trial' => _('Starting your free 30 day trial'),
'Success!' => _('Success!'),
'Thank you for choosing Unraid OS!' => _('Thank you for choosing Unraid OS!'),
'Thank you for installing Connect!' => _('Thank you for installing Connect!'),
'Thank you for purchasing an Unraid {0} Key!' => sprintf(_('Thank you for purchasing an Unraid %s Key!'), '{0}'),
'Thank you for upgrading to an Unraid {0} Key!' => sprintf(_('Thank you for upgrading to an Unraid %s Key!'), '{0}'),
'The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.' => _('The Connect dashboard links to relevant sections of the webgui, allowing quick access to those settings and server sections.'),
'The logs may contain sensitive information so do not post them publicly.' => _('The logs may contain sensitive information so do not post them publicly.'),
'The primary method of support for Unraid Connect is through our forums and Discord.' => _('The primary method of support for Unraid Connect is through our forums and Discord.'),
'Then go to Tools > Registration to manually install it' => _('Then go to Tools > Registration to manually install it'),
'This may indicate a complex network that will not work with this Remote Access solution.' => _('This may indicate a complex network that will not work with this Remote Access solution.'),
'This update will require a reboot' => _('This update will require a reboot'),
'Toggle on/off server accessibility with dynamic remote access. Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.' => _('Toggle on/off server accessibility with dynamic remote access.') . ' ' . _('Automatically turn on UPnP and open a random WAN port on your router at the click of a button and close off access in seconds.'),
'Too Many Devices' => _('Too Many Devices'),
'Transfer License to New Flash' => _('Transfer License to New Flash'),
'Trial Expired, see options below' => _('Trial Expired, see options below'),
'Trial Expired' => _('Trial Expired'),
'Trial Key Created' => _('Trial Key Created'),
'Trial Key Creation Failed' => _('Trial Key Creation Failed'),
'Trial Key Expired {0}' => sprintf(_('Trial Key Expired %s'), '{0}'),
'Trial Key Expired at {0}' => sprintf(_('Trial Key Expired at %s'), '{0}'),
'Trial Key Expires at {0}' => sprintf(_('Trial Key Expires at %s'), '{0}'),
'Trial Key Expires in {0}' => sprintf(_('Trial Key Expires in %s'), '{0}'),
'Trial Requires Internet Connection' => _('Trial Requires Internet Connection'),
'Trial' => _('Trial'),
'Unable to check for OS updates' => _('Unable to check for OS updates'),
'Unable to fetch client WAN IPv4' => _('Unable to fetch client WAN IPv4'),
'Unable to open release notes' => _('Unable to open release notes'),
'Unknown error' => _('Unknown error'),
'unlimited' => _('unlimited'),
'Unraid {0} Available' => sprintf(_('Unraid %s Available'), '{0}'),
'Unraid {0} Update Available' => sprintf(_('Unraid %s Update Available'), '{0}'),
'Unraid {0}' => sprintf(_('Unraid %s'), '{0}'),
'Unraid Connect Error' => _('Unraid Connect Error'),
'Unraid Connect Forums' => _('Unraid Connect Forums'),
'Unraid Connect Install Failed' => _('Unraid Connect Install Failed'),
'Unraid Contact Page' => _('Unraid Contact Page'),
'Unraid Discord' => _('Unraid Discord'),
'Unraid logo animating with a wave like effect' => _('Unraid logo animating with a wave like effect'),
'Unraid OS {0} Released' => sprintf(_('Unraid OS %s Released'), '{0}'),
'Unraid OS {0} Update Available' => sprintf(_('Unraid OS %s Update Available'), '{0}'),
'Unraid OS Update Available' => _('Unraid OS Update Available'),
'unraid-api is offline' => _('unraid-api is offline'),
'Up-to-date' => _('Up-to-date'),
'Update Available' => _('Update Available'),
'Update Unraid OS confirmation required' => _('Update Unraid OS confirmation required'),
'Update Unraid OS' => _('Update Unraid OS'),
'Updating 3rd party drivers' => _('Updating 3rd party drivers'),
'Upgrade Key' => _('Upgrade Key'),
'Upgrade' => _('Upgrade'),
'Uptime {0}' => sprintf(_('Uptime %s'), '{0}'),
'USB Flash device error' => _('USB Flash device error'),
'USB Flash has no serial number' => _('USB Flash has no serial number'),
'Version available for restore {0}' => sprintf(_('Version available for restore %s'), '{0}'),
'Version: {0}' => sprintf(_('Version: %s'), '{0}'),
'View Available Updates' => _('View Available Updates'),
'View Changelog & Update' => _('View Changelog & Update'),
'View Changelog for {0}' => sprintf(_('View Changelog for %s'), '{0}'),
'View Changelog' => _('View Changelog'),
'View release notes' => _('View release notes'),
'We recommend backing up your USB Flash Boot Device before starting the update.' => _('We recommend backing up your USB Flash Boot Device before starting the update.'),
'year' => sprintf(_('%s year'), '{n}') . ' | ' . sprintf(_('%s years'), '{n}'),
'You can also manually create a new backup by clicking the Create Flash Backup button.' => _('You can also manually create a new backup by clicking the Create Flash Backup button.'),
'You can manually create a backup by clicking the Create Flash Backup button.' => _('You can manually create a backup by clicking the Create Flash Backup button.'),
'You have already activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have already activated the Flash Backup feature via the Unraid Connect plugin.'),
'You have exceeded the number of devices allowed for your license. Please remove a device before adding another.' => _('You have exceeded the number of devices allowed for your license. Please remove a device before adding another.'),
'You have not activated the Flash Backup feature via the Unraid Connect plugin.' => _('You have not activated the Flash Backup feature via the Unraid Connect plugin.'),
'You may still update to releases dated prior to your update expiration date.' => _('You may still update to releases dated prior to your update expiration date.'),
'You\'re one step closer to enhancing your Unraid experience' => _('You\'re one step closer to enhancing your Unraid experience'),
'Your {0} Key has been replaced!' => sprintf(_('Your %s Key has been replaced!'), '{0}'),
'Your free Trial key provides all the functionality of an Unleashed Registration key' => _('Your free Trial key provides all the functionality of an Unleashed Registration key'),
'Your Trial has expired' => _('Your Trial has expired'),
'Your Trial key has been extended!' => _('Your Trial key has been extended!'),
];
}
public function getTranslations()
{
return $this->translations ?? [];
}
/**
* @param $urlEncode {bool}
* @return string
*/
public function getTranslationsJson($urlEncode = false)
{
if ($urlEncode) {
return rawurlencode(json_encode($this->getTranslations(), JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE));
}
return json_encode($this->getTranslations(), JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,14 @@
{
".nuxt/nuxt-custom-elements/entries/unraid-components.client.css": {
"file": "_nuxt/unraid-components.client-fad7c220.css",
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.css"
},
".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs": {
"css": [
"_nuxt/unraid-components.client-fad7c220.css"
],
"file": "_nuxt/unraid-components.client-cd1b3939.js",
"isEntry": true,
"src": ".nuxt/nuxt-custom-elements/entries/unraid-components.client.mjs"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,173 @@
Menu="About:20"
Title="Downgrade OS"
Icon="icon-update"
Tag="upload"
---
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
// Create an instance of the RebootDetails class
$rebootDetails = new RebootDetails();
/**
* @note icon-update is rotated via CSS in myservers1.php
*
* If /boot/previous/bzroot exists, then the user has the option to downgrade to the previous version.
* Parse the text file /boot/previous/changes.txt to get the version number of the previous version.
* Then we move some files around and reboot.
*/
$restoreVersion = $restoreBranch = $restoreVersionReleaseDate = 'unknown';
$restoreExists = file_exists('/boot/previous/bzroot');
$restoreChangelogPath = '/boot/previous/changes.txt';
$serverNameEscaped = htmlspecialchars(str_replace(' ', '_', strtolower($var['NAME'])));
if (file_exists($restoreChangelogPath)) {
exec("head -n4 $restoreChangelogPath", $rows);
foreach ($rows as $row) {
$i = stripos($row,'version');
if ($i !== false) {
[$restoreVersion, $restoreVersionReleaseDate] = explode(' ', trim(substr($row, $i+7)));
break;
}
}
$restoreBranch = strpos($restoreVersion, 'rc') !== false
? _('Next')
: (strpos($restoreVersion, 'beta') !== false
? _('Beta')
: _('Stable'));
}
?>
<script>
const nchan_diagnostics = new NchanSubscriber('/sub/diagnostics', { subscriber: 'websocket' });
const reportUrl = new URL('https://forums.unraid.net/bug-reports/');
let diagnosticsFile = '';
nchan_diagnostics.on('message', function(data) {
if (data == '_DONE_') {
nchan_diagnostics.stop();
$('.sweet-alert').hide('fast').removeClass('nchan');
swal.close();
$('div.spinner').show('slow');
location = diagnosticsFile;
setTimeout(() => {
cleanupDiagnostics();
reportAfterDiagnosticsDownload();
}, 2000);
} else if (data) {
let box = $('pre#swaltext');
box.html(box.html() + '<br>' + data).scrollTop(box[0].scrollHeight);
}
});
function downloadDiagnostics() {
const tzoffset = (new Date()).getTimezoneOffset() * 60000; // offset in milliseconds
const localISOTime = (new Date(Date.now() - tzoffset));
const year = localISOTime.getFullYear();
const month = String(localISOTime.getMonth() + 1).padStart(2, '0');
const day = String(localISOTime.getDate()).padStart(2, '0');
const hours = String(localISOTime.getHours()).padStart(2, '0');
const minutes = String(localISOTime.getMinutes()).padStart(2, '0');
const dateOutput = `${year}${month}${day}_${hours}${minutes}`;
const zipName = '<?=$serverNameEscaped?>-diagnostics-' + dateOutput + '.zip';
nchan_diagnostics.start();
$.post(
'/webGui/include/Download.php',
{
cmd: 'diag',
file: zipName,
anonymize: '',
},
function(zip) {
if (!zip) {
return nchan_diagnostics.stop();
}
diagnosticsFile = zip;
swal({
title: "_(Downloading)_...",
text: "/boot/logs" + zip + "<hr><pre id='swaltext'></pre>",
html: true,
animation: 'none',
showConfirmButton: false,
});
$('.sweet-alert').addClass('nchan');
$('button.confirm').prop('disabled', true);
},
);
}
function reportAfterDiagnosticsDownload() {
$('div.spinner').hide('fast');
swal({
title: "_(Open a bug report)_",
text: "_(Create a bug report on our forums with a description of the issue along with your diagsnotics)_",
html: true,
type: 'warning',
showCancelButton: true,
confirmButtonText: "<?= _('Create Bug Report') ?>",
cancelButtonText: "<?= _('Close') ?>",
}, function(confirm) {
if (!confirm) {
return false;
}
window.open(reportUrl, '_blank');
});
}
function cleanupDiagnostics() {
if (document.hasFocus()) {
return $.post('/webGui/include/Download.php', { cmd: 'delete', file: diagnosticsFile });
}
setTimeout(cleanupDiagnostics, 2000);
}
function startDowngrade() {
$('div.spinner').show('slow');
$.get(
'/plugins/dynamix.plugin.manager/include/Downgrade.php',
{
version: '<?=$restoreVersion?>',
},
function() {
refresh();
}
);
}
function confirmDowngrade() {
swal({
title: "_(Confirm Downgrade)_",
text: "<?= $restoreVersion ?><br>_(A reboot will be required)_",
html: true,
type: 'warning',
showCancelButton: true,
confirmButtonText: "<?= _('Confirm') ?>",
cancelButtonText: "<?= _('Cancel') ?>",
}, function(confirm) {
if (!confirm) {
return false;
}
startDowngrade();
});
}
</script>
<unraid-i18n-host>
<unraid-downgrade-os
reboot-version="<?= $rebootDetails->getRebootVersion() ?>"
restore-version="<?= $restoreExists && $restoreVersion != 'unknown' ? $restoreVersion : '' ?>"
restore-release-date="<?= $restoreExists && $restoreVersionReleaseDate != 'unknown' ? $restoreVersionReleaseDate : '' ?>"></unraid-downgrade-os>
</unraid-i18n-host>

View File

@@ -1,11 +1,10 @@
Menu="About"
Menu="About:10"
Title="Update OS"
Icon="icon-update"
Tag="upload"
---
<?PHP
/* Copyright 2005-2022, Lime Technology
* Copyright 2012-2022, Bergware International.
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -14,186 +13,38 @@ Tag="upload"
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
require_once "$docroot/plugins/dynamix.my.servers/include/reboot-details.php";
$rebootDetails = new RebootDetails();
?>
<?
$version = $branch = $date = _('unknown');
$bzroot = file_exists('/boot/previous/bzroot');
$check = $notify['unraidos'] ? 0 : 1;
$changes = '/boot/previous/changes.txt';
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
if (file_exists($changes)) {
exec("head -n4 $changes",$rows);
foreach ($rows as $row) {
$i = stripos($row,'version');
if ($i !== false) {
[$version,$date] = explode(' ',trim(substr($row,$i+7)));
break;
}
}
$branch = strpos($version,'rc')!==false ? _('Next') : (strpos($version,'beta')!==false ? _('Beta') : _('Stable'));
}
$reboot = preg_match("/^\*\*(REBOOT REQUIRED|DOWNGRADE)/",@file_get_contents("$docroot/plugins/unRAIDServer/README.md",false,null,0,20));
?>
<style>
ul,li{margin:0;padding-top:0;padding-bottom:0}
pre.pre{margin:30px 0}
pre>p{margin:0;padding:0}
pre#swaltext{height:600px!important}
@media (max-width:960px){pre#swaltext{height:400px!important}}
@media (max-width:960px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
@media (max-height:768px){pre#swaltext{height:400px!important}}
@media (max-height:768px){.sweet-alert.nchan{height:600px;width:900px;margin-left:-470px}}
input[value="_(Install)_"],input[value="_(Update)_"],input[value="_(Restore)_"]{margin:0}
<?if ($themes1):?>
span.vhshift{margin-top:13px!important}
<?endif;?>
</style>
<script>
var diagnosticsFile = "";
var nchan_diagnostics = new NchanSubscriber('/sub/diagnostics',{subscriber:'websocket'});
var original = null;
const args = {};
nchan_diagnostics.on('message', function(data) {
if (data == '_DONE_') {
nchan_diagnostics.stop();
$('.sweet-alert').hide('fast').removeClass('nchan');
swal.close();
location = diagnosticsFile;
setTimeout(cleanUp,4000);
} else if (data) {
let box = $('pre#swaltext');
box.html(box.html()+'<br>'+data).scrollTop(box[0].scrollHeight);
}
});
function openInstall(cmd,title,plg) {
if (cmd == null) {
openPlugin(args.cmd,args.title,args.plg);
return;
}
args.cmd = cmd;
args.title = title;
args.plg = plg;
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{cmd:'alert'},function(data) {
if (data==0) {
// no alert message - proceed with update
setTimeout(openInstall);
} else {
// show alert message and ask for confirmation
openAlert("showchanges <?=$alerts?>","_(Alert Message)_",'openInstall');
}
});
}
function update_table(branch) {
if (original) {
if (branch != original) branch = '';
} else {
if (branch) original = branch;
}
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{system:true,branch:branch},function(data) {
data = data.split('\0');
updateInfo(data[0]);
$('#os_table').trigger('update');
});
}
function downgrade() {
swal({title:"_(Diagnostics)_",text:"_(Please provide diagnostics when experiencing problems)_<br>_(Post these in the forums)_",html:true,type:'warning',showCancelButton:true,confirmButtonText:"<?=_('Diagnostics')?>",cancelButtonText:"<?=_('Restore')?>"},function(diag){
if (diag) {
// get diagnostics and then downgrade
setTimeout(function(){diagnostics(zipfile());},250);
} else {
// downgrade immediately
$.get('/plugins/dynamix.plugin.manager/include/Downgrade.php',{version:'<?=$version?>'},function(){refresh();});
}
});
}
function updateInfo(data) {
var updates = data.split('\n');
for (var n=0,update; update=updates[n]; n++) {
var fields = update.split('\r');
for (var i=0,field; field=fields[i]; i++) {
var row = field.split('::');
$('#'+row[0]).attr('data',row[1]).html(row[2]);
}
}
}
function initlist() {
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{init:true,system:true,check:<?=$check?>},function(data) {
$('#os_list').html(data);
<?if ($bzroot):?>
$('#previous').show();
<?endif;?>
loadlist();
});
}
function warning (data) {
$('#change_branch').prop('disabled',true);
return data.replace('green','orange').replace("<?=_('up-to-date')?>","<?=_('Reboot')?>").replace('checking','warning');
}
function loadlist(id,check) {
$.get('/plugins/dynamix.plugin.manager/include/ShowPlugins.php',{system:true,audit:id,check:check||<?=$check?>},function(data) {
var list = $('#os_list');
if (id) {
var cmd = id.split(':');
var tr = 'tr#'+cmd[0].replace(/[\. _]/g,'');
switch (cmd[1]) {
case 'update' : data = warning(data);
case 'return' : updateInfo(data); break;
case 'install': list.find(tr).remove(); list.append(warning(data)); break;
}
} else {
<?if (!$reboot):?>
updateInfo(data);
<?else:?>
updateInfo(warning(data));
<?endif;?>
}
$('#os_table').trigger('update');
$('#checkos').prop('disabled',false);
<?if ($reboot):?>
$('#change_branch').prop('disabled',true);
<?endif;?>
});
}
function cleanUp() {
function cleanUpFlashBackup(zip) {
if (document.hasFocus()) {
$.post('/webGui/include/Download.php',{cmd:'delete',file:diagnosticsFile},function(){
$.get('/plugins/dynamix.plugin.manager/include/Downgrade.php',{version:'<?=$version?>'},function(){refresh();});
});
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_").prop('disabled',false);
$('div.spinner').hide('slow');
$('#pleaseWait').hide('slow');
$.post('/webGui/include/Download.php',{cmd:'unlink',file:zip});
} else {
setTimeout(cleanUp,2000);
setTimeout(function(){cleanUpFlashBackup(zip);},2000);
}
}
function zipfile(){
var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0,-1);
return '<?=$zip?>-diagnostics-'+localISOTime.substr(0,16).replace(/[-:]/g,'').replace('T','-')+'.zip';
}
function diagnostics(file) {
nchan_diagnostics.start();
$.post('/webGui/include/Download.php',{cmd:'diag',file:file,anonymize:''},function(zip) {
function flashBackup() {
$('input[value="_(Flash backup)_"]').val('_(Creating Flash backup)_...').prop('disabled',true);
$('div.spinner').show('slow');
$('#pleaseWait').show('slow');
$.post('/webGui/include/Download.php',{cmd:'backup'},function(zip) {
if (zip) {
diagnosticsFile = zip;
swal({title:"_(Downloading)_...",text:"/boot/logs"+zip+"<hr><pre id='swaltext'></pre>",html:true,animation:'none',showConfirmButton:false});
$('.sweet-alert').addClass('nchan');
$('button.confirm').prop('disabled',true);
location = '/'+zip;
setTimeout(function(){cleanUpFlashBackup(zip);},6000);
} else {
nchan_diagnostics.stop();
$('input[value="_(Creating Flash backup)_..."]').val("_(Flash backup)_");
$('div.spinner').hide('slow');
$('#pleaseWait').hide('slow');
swal({title:"_(Creation error)_",text:"_(Insufficient free disk space available)_",type:'error',html:true,confirmButtonText:"_(Ok)_"});
}
});
}
$(function() {
initlist();
$('.tabs').append("<span class='status vhshift'><input type='button' id='checkos' value=\"_(Check for Updates)_\" onclick='openPlugin(\"plugin checkos\",\"_(System Update Check)_\",\":return\")' disabled></span>");
});
</script>
<table class='tablesorter plugins shift' id='os_table'>
<thead><tr><th></th><th>_(Component)_</th><th>_(Author)_</th><th>_(Version)_</th><th>_(Status)_</th><th>_(Branch)_</th></tr></thead>
<tbody id="os_list"><tr><td colspan="6"></td></tr></tbody>
<?if ($bzroot):?>
<tbody id="previous" style="display:none"><tr><td><img src="/plugins/unRAIDServer/images/unRAIDServer.png" class="list"></td><td><b>_(Unraid OS)_ (_(previous)_)</b></td><td>LimeTech</td><td><?=$version?></td><td><input type="button" value="_(Restore)_" onclick="downgrade()"></td><td><?=$branch?></td></tbody>
<?endif;?>
</table>
<unraid-i18n-host>
<unraid-update-os reboot-version="<?= $rebootDetails->getRebootVersion() ?>"></unraid-update-os>
</unraid-i18n-host>

View File

@@ -20,6 +20,9 @@ require_once "$docroot/webGui/include/Secure.php";
$_SERVER['REQUEST_URI'] = 'plugins';
require_once "$docroot/webGui/include/Translations.php";
$tmpdir="/boot/deletemedowngrade.".uniqid();
mkdir($tmpdir);
exec("mv -f /boot/bz* $tmpdir");
exec("mv -f /boot/previous/* /boot");
$version = unscript(_var($_GET,'version'));
file_put_contents("$docroot/plugins/unRAIDServer/README.md","**"._('DOWNGRADE TO VERSION')." $version**");

View File

@@ -0,0 +1,270 @@
<?php
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
/**
* Abstracting this code into a separate file allows us to use it in multiple places without duplicating code.
* 1. unraidcheck script can call this
* require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
* $unraidOsCheck = new UnraidOsCheck();
* $unraidOsCheck->checkForUpdate();
*
* 2. Unraid webgui web components can GET this file with action params to get updates, ignore updates, etc.
* - EX: Unraid webgui web components can check for updates via a GET request and receive a response with the json file directly
* - this is useful for the UPC to check for updates and display a model based on the value
* - `/plugins/dynamix.plugin.manager/scripts/unraidcheck.php?json=true`
* - note the json=true query param to receive a json response
*
* @param action {'check'|'removeAllIgnored'|'removeIgnoredVersion'|'ignoreVersion'} - the action to perform
* @param version {string} - the version to ignore or remove
* @param json {string} - if set to true, will return the json response from the external request
* @param altUrl {URL} - if set, will use this url instead of the default
*/
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
class UnraidOsCheck
{
private const BASE_RELEASES_URL = 'https://releases.unraid.net/os';
private const JSON_FILE_IGNORED = '/tmp/unraidcheck/ignored.json';
private const JSON_FILE_IGNORED_KEY = 'updateOsIgnoredReleases';
private const JSON_FILE_RESULT = '/tmp/unraidcheck/result.json';
private const PLG_PATH = '/var/log/plugins/unRAIDServer.plg';
public function __construct()
{
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
if ($isGetRequest && $getHasAction) {
$this->handleGetRequestWithActions();
}
}
private function handleGetRequestWithActions()
{
switch ($_GET['action']) {
case 'check':
$this->checkForUpdate();
break;
case 'removeAllIgnored':
$this->removeAllIgnored();
break;
case 'removeIgnoredVersion':
if (isset($_GET['version'])) {
$this->removeIgnoredVersion($_GET['version']);
}
break;
case 'ignoreVersion':
if (isset($_GET['version'])) {
$this->ignoreVersion($_GET['version']);
}
break;
default:
$this->respondWithError(400, "Unhandled action");
break;
}
}
public function getUnraidOSCheckResult()
{
if (file_exists(self::JSON_FILE_RESULT)) {
return $this->readJsonFile(self::JSON_FILE_RESULT);
}
}
public function getIgnoredReleases()
{
if (!file_exists(self::JSON_FILE_IGNORED)) {
return [];
}
$ignoredData = $this->readJsonFile(self::JSON_FILE_IGNORED);
if (is_array($ignoredData) && array_key_exists(self::JSON_FILE_IGNORED_KEY, $ignoredData)) {
return $ignoredData[self::JSON_FILE_IGNORED_KEY];
}
return [];
}
/** @todo clean up this method to be more extensible */
public function checkForUpdate()
{
// Multi-language support
if (!function_exists('_')) {
function _($text) {return $text;}
}
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix', true));
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
$params = [];
$params['branch'] = plugin('category', self::PLG_PATH, 'stable');
$params['current_version'] = plugin('version', self::PLG_PATH) ?: _var($var,'version');
if (_var($var,'regExp')) $params['update_exp'] = date('Y-m-d', _var($var,'regExp')*1);
$defaultUrl = self::BASE_RELEASES_URL;
// pass a param of altUrl to use the provided url instead of the default
$parsedAltUrl = (array_key_exists('altUrl',$_GET) && $_GET['altUrl']) ? $_GET['altUrl'] : null;
// if $parsedAltUrl pass to params
if ($parsedAltUrl) $params['altUrl'] = $parsedAltUrl;
$urlbase = $parsedAltUrl ?? $defaultUrl;
$url = $urlbase.'?'.http_build_query($params);
$response = "";
// use error handler to convert warnings from file_get_contents to errors so they can be captured
function warning_as_error($severity, $message, $filename, $lineno) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler("warning_as_error");
try {
$response = file_get_contents($url);
} catch (Exception $e) {
$response = json_encode(array('error' => $e->getMessage()), JSON_PRETTY_PRINT);
}
restore_error_handler();
$responseMutated = json_decode($response, true);
if (!$responseMutated) {
$response = json_encode(array('error' => 'Invalid response from '.$urlbase), JSON_PRETTY_PRINT);
$responseMutated = json_decode($response, true);
}
// add params that were used for debugging
$responseMutated['params'] = $params;
// store locally for UPC to access
$this->writeJsonFile(self::JSON_FILE_RESULT, $responseMutated);
// if we have a query param of json=true then just output the json
if (array_key_exists('json',$_GET) && $_GET['json']) {
header('Content-Type: application/json');
echo $response;
exit(0);
}
// send notification if a newer version is available and not ignored
$isNewerVersion = array_key_exists('isNewer',$responseMutated) ? $responseMutated['isNewer'] : false;
$isReleaseIgnored = in_array($responseMutated['version'], $this->getIgnoredReleases());
if ($responseMutated && $isNewerVersion && !$isReleaseIgnored) {
$output = _var($notify,'plugin');
$server = strtoupper(_var($var,'NAME','server'));
$newver = (array_key_exists('version',$responseMutated) && $responseMutated['version']) ? $responseMutated['version'] : 'unknown';
$script = '/usr/local/emhttp/webGui/scripts/notify';
$event = "System - Unraid [$newver]";
$subject = "Notice [$server] - Version update $newver";
$description = "A new version of Unraid is available";
exec("$script -e ".escapeshellarg($event)." -s ".escapeshellarg($subject)." -d ".escapeshellarg($description)." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
}
exit(0);
}
private function removeAllIgnored()
{
if (file_exists(self::JSON_FILE_IGNORED)) {
$this->deleteJsonFile(self::JSON_FILE_IGNORED);
$this->respondWithSuccess([]);
}
// fail silently if file doesn't exist
}
private function removeIgnoredVersion($removeVersion)
{
if ($this->isValidSemVerFormat($removeVersion)) {
if (file_exists(self::JSON_FILE_IGNORED)) {
$existingData = $this->readJsonFile(self::JSON_FILE_IGNORED);
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
$existingData[self::JSON_FILE_IGNORED_KEY] = array_diff($existingData[self::JSON_FILE_IGNORED_KEY], [$removeVersion]);
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
$this->respondWithSuccess($existingData);
} else {
$this->respondWithError(400, "No versions to remove in the JSON file");
}
} else {
$this->respondWithError(400, "No JSON file found");
}
} else {
$this->respondWithError(400, "Invalid removeVersion format");
}
}
private function ignoreVersion($version)
{
if ($this->isValidSemVerFormat($version)) {
$newData = [$this::JSON_FILE_IGNORED_KEY => [$version]];
$existingData = file_exists(self::JSON_FILE_IGNORED) ? $this->readJsonFile(self::JSON_FILE_IGNORED) : [];
if (isset($existingData[self::JSON_FILE_IGNORED_KEY])) {
$existingData[self::JSON_FILE_IGNORED_KEY][] = $version;
} else {
$existingData[self::JSON_FILE_IGNORED_KEY] = [$version];
}
$this->writeJsonFile(self::JSON_FILE_IGNORED, $existingData);
$this->respondWithSuccess($existingData);
} else {
$this->respondWithError(400, "Invalid version format");
}
}
private function isValidSemVerFormat($version)
{
return preg_match('/^\d+\.\d+(\.\d+)?(-.+)?$/', $version);
}
private function readJsonFile($file)
{
return @json_decode(@file_get_contents($file), true) ?? [];
}
private function writeJsonFile($file, $data)
{
if (!is_dir(dirname($file))) { // prevents errors when directory doesn't exist
mkdir(dirname($file));
}
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}
private function deleteJsonFile($file)
{
unlink($file);
}
private function respondWithError($statusCode, $message)
{
http_response_code($statusCode);
echo $message;
}
private function respondWithSuccess($data)
{
http_response_code(200);
header('Content-Type: application/json');
echo json_encode($data, JSON_PRETTY_PRINT);
}
}
// Instantiate and handle the request for GET requests with actions vars are duplicated here for multi-use of this file
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
$getHasAction = $_GET !== null && !empty($_GET) && isset($_GET['action']);
if ($isGetRequest && $getHasAction) {
new UnraidOsCheck();
}

View File

@@ -24,7 +24,7 @@ function newurl($url) {
return str_replace($oldURL,$newURL,$url);
}
function searchLink(&$db,$url) {
if ($url) for ($i = 0; $i < count($db); $i++) if ($db[$i]['PluginURL']==$url) return $db[$i]['Support'];
if ($url) for ($i = 0; $i < count($db); $i++) if ( ($db[$i]['PluginURL']??null)==$url) return $db[$i]['Support']??null;
}
$type = $argv[1]??''; // plugin or language

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -16,6 +16,7 @@ $docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix', true));
// Multi-language support

View File

@@ -357,7 +357,7 @@ function plugin($method, $plugin_file, &$error) {
if (isset($file->attributes()->Method)) {
if (!in_array($method, explode(" ", $file->attributes()->Method))) continue;
} elseif ($method != 'install') continue;
$name = $file->attributes()->Name;
$name = $file->attributes()->Name ?: '';
// bergware - check Unraid version dependency (if present)
$min = $file->attributes()->Min;
if ($min && version_compare($unraid['version'],$min,'<')) {

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -16,7 +16,7 @@ $docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
// this command will set the $notify array
extract(parse_plugin_cfg('dynamix',true));
// Multi-language support

View File

@@ -23,7 +23,7 @@ $login_locale = _var($display,'locale');
require_once "$docroot/webGui/include/Translations.php";
$file = realpath($argv[1]??'');
$valid = ['/var/tmp/','/tmp/plugins/'];
$valid = ['/var/tmp/','/tmp/plugins/','/boot/previous'];
$good = false;
foreach ($valid as $check) if (strncmp($file,$check,strlen($check))===0) $good = true;

View File

@@ -12,35 +12,8 @@
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/plugins/dynamix.plugin.manager/include/UnraidCheck.php";
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/plugins/dynamix.plugin.manager/include/PluginHelpers.php";
// Multi-language support
if (!function_exists('_')) {
function _($text) {return $text;}
}
extract(parse_plugin_cfg('dynamix', true));
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
$script = "$docroot/webGui/scripts/notify";
$server = strtoupper(_var($var,'NAME','server'));
$output = _var($notify,'plugin');
$builtin = ['unRAIDServer'];
foreach ($builtin as $name) {
$plg = "$name.plg";
plugin('check',$plg);
$file = "/tmp/plugins/$plg";
$old = plugin('version', "/var/log/plugins/$plg");
$new = plugin('version', $file);
// silently suppress bad download of PLG file
if (version_compare($new,$old,'>')) {
exec("$script -e ".escapeshellarg("System - $name [$new]")." -s ".escapeshellarg("Notice [$server] - Version update $new")." -d ".escapeshellarg("A new version of $name is available")." -i ".escapeshellarg("normal $output")." -l '/Tools/Update' -x");
}
}
exit(0);
?>
$unraidOsCheck = new UnraidOsCheck();
$unraidOsCheck->checkForUpdate();

View File

@@ -755,6 +755,15 @@ private static $encoding = 'UTF-8';
$arrWhitelistGPUClassIDregex = '/^(0001|03)/';
$arrWhitelistAudioClassIDregex = '/^(0403)/';
# "System peripheral [0880]" "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]" -pff "Global unichip corp. [1ac1]" "Coral Edge Tpu [089a]"
# typeid productid
# file is csv typeid:productid
#
if (is_file("/boot/config/VMPCIOverride.cfg")) {
$arrWhiteListOverride = str_getcsv(file_get_contents("/boot/config/VMPCIOverride.cfg")) ;
}
$arrWhiteListOverride[] = "0880:089a" ;
$arrValidPCIDevices = [];
exec("lspci -m -nn 2>/dev/null", $arrAllPCIDevices);
@@ -769,6 +778,9 @@ private static $encoding = 'UTF-8';
$boolBlacklisted = true;
}
$overrideCheck = "{$arrMatch['typeid']}:{$arrMatch['productid']}" ;
if (in_array($overrideCheck,$arrWhiteListOverride) ) $boolBlacklisted = false;
$strClass = 'other';
if (preg_match($arrWhitelistGPUClassIDregex, $arrMatch['typeid'])) {
$strClass = 'vga';
@@ -954,6 +966,16 @@ private static $encoding = 'UTF-8';
return $arrValidMachineTypes;
}
function ValidateMachineType($machinetype) {
$machinetypes=getValidMachineTypes();
$type = substr($machinetype,0,strpos($machinetype,'-',3));
foreach($machinetypes as $machinetypekey => $machinedetails){
$check_type = substr($machinetypekey,0,strlen($type));
if ($check_type == $type) break;
}
return($machinetypekey) ;
}
function getLatestMachineType($strType = 'i440fx') {
$arrMachineTypes = getValidMachineTypes();

View File

@@ -82,7 +82,7 @@
if (auto === 'true' || auto == '1') {
auto = true;
connect();
setTimeout(connect, 3000);
}
function spice_error(e)

View File

@@ -48,7 +48,7 @@
'uuid' => $lv->domain_generate_uuid(),
'clock' => 'localtime',
'arch' => 'x86_64',
'machine' => 'pc',
'machine' => 'pc-i440fx',
'mem' => 1024 * 1024,
'maxmem' => 1024 * 1024,
'password' => '',
@@ -410,6 +410,12 @@
</blockquote>
</div>
<?
if (!isset($arrValidMachineTypes[$arrConfig['domain']['machine']])) {
$arrConfig['domain']['machine'] = ValidateMachineType($arrConfig['domain']['machine']);
}
?>
<table>
<tr class="advanced">
<td>_(Machine)_:</td>
@@ -1036,7 +1042,7 @@
<tr class="<?if ($arrGPU['id'] != 'virtual') echo 'was';?>advanced vncmodel">
<td>_(VM Console Video Driver)_:</td>
<td>
<select id="vncmodel" name="gpu[<?=$i?>][model]" class="narrow" title="_(video for VNC)_">
<select id="vncmodel" name="gpu[<?=$i?>][model]" class="narrow" title="_(video for VM Console)_">
<?mk_dropdown_options($arrValidVNCModels, $arrGPU['model']);?>
</select>
</td>
@@ -1044,12 +1050,12 @@
<tr class="vncpassword">
<td>_(VM Console Password)_:</td>
<td><input type="password" name="domain[password]" autocomplete='new-password' value="<?=$arrGPU['password']?>" title="_(password for VNC)_" placeholder="_(password for VNC)_ (_(optional)_)" /></td>
<td><input type="password" name="domain[password]" autocomplete='new-password' value="<?=$arrGPU['password']?>" title="_(password for VM Console)_" placeholder="_(password for VM Console)_ (_(optional)_)" /></td>
</tr>
<tr class="<?if ($arrGPU['id'] != 'virtual') echo 'was';?>advanced vnckeymap">
<td>_(VM Console Keyboard)_:</td>
<td>
<select name="gpu[<?=$i?>][keymap]" title="_(keyboard for VNC)_">
<select name="gpu[<?=$i?>][keymap]" title="_(keyboard for VM Console)_">
<?mk_dropdown_options($arrValidKeyMaps, $arrGPU['keymap']);?>
</select>
</td>

View File

@@ -537,6 +537,9 @@ function formatWarning(val) {
<? elseif (_var($var,'configValid')=="invalid"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Too many attached devices. Please consider upgrading your)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
<? elseif (_var($var,'configValid')=="ineligible"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Ineligible to run this version of Unraid OS. Please consider extending your)_ <a href="/Tools/Registration">_(registration key)_</a>.</td></tr>
<? elseif (_var($var,'configValid')=="nokeyserver"):?>
<tr><td><?status_indicator()?>**_(Stopped)_.**</td><td><input type="submit" name="cmdStart" value="_(Start)_" disabled></td>
<td>_(Cannot contact key-server. Please check your)_ <a href="/Settings/NetworkSettings">_(network settings)_</a>.</td></tr>

View File

@@ -27,6 +27,9 @@ $bgcolor = in_array($display['theme'],['white','azure']) ? '#f2f2f2' : '#1c1c
$mode = ['Disabled','Hourly','Daily','Weekly','Monthly'];
$days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
function disabled_if($condition) {
if ($condition !== false) echo ' disabled';
}
function sanitize(&$val) {
$data = explode('.',str_replace([' ',','],['','.'],$val));
$last = array_pop($data);
@@ -597,10 +600,10 @@ _(Spin down delay)_:
_(File system status)_:
: <?=_(_var($disk,'fsStatus'))?>&nbsp;
<?$disabled = ((_var($var,'fsState')=="Stopped" && _var($var,'mdState')=="SWAP_DSBL") || _var($var,'fsState')=="Started" || _var($disk,'fsStatus')=='Mounted') || _var($disk,'uuid') ? "disabled" : ""?>
<?$fsTypeImmutable = ((_var($var,'fsState')=="Stopped" && _var($var,'mdState')=="SWAP_DSBL") || _var($var,'fsState')=="Started" || _var($disk,'fsStatus')=='Mounted') || _var($disk,'uuid')?>
<?if (diskType('Data') || _var($disk,'slots',0)==1):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=$disabled?>>
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="changeFsType()" <?=disabled_if($fsTypeImmutable)?>>
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
<?=mk_option(_var($disk,'fsType'), "xfs", _('xfs'))?>
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
@@ -616,39 +619,38 @@ _(File system type)_:
<?elseif (_var($disk,'slots',0)>1):?>
_(File system type)_:
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
: <select id="diskFsType" name="diskFsType.<?=_var($disk,'idx',0)?>" onchange="selectDiskFsProfile(<?=_var($disk,'devices',0)?>,0)" <?=disabled_if($fsTypeImmutable)?>>
<?=mk_option(_var($disk,'fsType'), "auto", _('auto'))?>
<?=mk_option(_var($disk,'fsType'), "zfs", _('zfs'))?>
<?=mk_option(_var($disk,'fsType'), "btrfs", _('btrfs'))?>
<?=mk_option(_var($disk,'fsType'), "luks:zfs", _('zfs')." - "._('encrypted'))?>
<?=mk_option(_var($disk,'fsType'), "luks:btrfs", _('btrfs')." - "._('encrypted'))?>
</select>
<select id="diskFsProfileBTRFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
<select id="diskFsProfileBTRFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" <?=disabled_if($fsTypeImmutable)?>>
<?=mk_option(_var($disk,'fsProfile'),"single", _('single'))?>
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid0", _('raid0'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"raid1", _('raid1'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid1c3", _('raid1c3'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid1c4", _('raid1c4'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid10", _('raid10'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raid5", _('raid5'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raid6", _('raid6'))?>
</select>
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'devices',0)?>,0)" <?=$disabled?>>
<?if (_var($disk,'devices',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
<?if (_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
<?if ((_var($disk,'devices',0)%2)==0 || (_var($disk,'devices',0)%3)==0 || (_var($disk,'devices',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
<?if (_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
<?if (_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
<?if (_var($disk,'devices',0)>=5) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
<select id="diskFsProfileZFS" name="diskFsProfile.<?=_var($disk,'idx',0)?>" style="display:none" onchange="selectDiskFsWidth(<?=_var($disk,'devices',0)?>,0)" <?=disabled_if($fsTypeImmutable)?>>
<?if ($fsTypeImmutable||_var($disk,'devices',0)==1) echo mk_option(_var($disk,'fsProfile'),"", _('single'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=2) echo mk_option(_var($disk,'fsProfile'),"", _('raid0'))?>
<?if ($fsTypeImmutable||(_var($disk,'devices',0)%2)==0 || (_var($disk,'devices',0)%3)==0 || (_var($disk,'devices',0)%4)==0) echo mk_option(_var($disk,'fsProfile'),"mirror", _('mirror'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=3) echo mk_option(_var($disk,'fsProfile'),"raidz1", _('raidz'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=4) echo mk_option(_var($disk,'fsProfile'),"raidz2", _('raidz2'))?>
<?if ($fsTypeImmutable||_var($disk,'devices',0)>=5) echo mk_option(_var($disk,'fsProfile'),"raidz3", _('raidz3'))?>
</select>
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=$disabled?>>
<select id="diskFsWidthZFS" name="diskFsWidth.<?=_var($disk,'idx',0)?>" style="display:none" <?=disabled_if($fsTypeImmutable)?>>
</select>
<?endif;?>
<div markdown="1" id="compression" style="display:none">
_(Compression)_:
<?$disabled = _var($disk,'fsStatus')=='Mounted' ? "disabled" : ""?>
: <select id="diskCompression" name="diskCompression.<?=_var($disk,'idx',0)?>" <?=$disabled?>>
: <select id="diskCompression" name="diskCompression.<?=_var($disk,'idx',0)?>" <?=disabled_if(_var($disk,'fsStatus')=='Mounted')?>>
<?=mk_option(_var($disk,'compression'), "off", _('Off'))?>
<?=mk_option(_var($disk,'compression'), "on", _('On'))?>
</select>
@@ -658,8 +660,7 @@ _(Compression)_:
<div markdown="1" id="autotrim" style="display:none">
_(Autotrim)_:
<?$disabled = _var($disk,'fsStatus')=='Mounted' ? "disabled" : ""?>
: <select id="diskAutotrim" name="diskAutotrim.<?=_var($disk,'idx',0)?>" <?=$disabled?>>
: <select id="diskAutotrim" name="diskAutotrim.<?=_var($disk,'idx',0)?>" <?=disabled_if(_var($disk,'fsStatus')=='Mounted')?>>
<?=mk_option(_var($disk,'autotrim'), "on", _('On'))?>
<?=mk_option(_var($disk,'autotrim'), "off", _('Off'))?>
</select>
@@ -668,8 +669,7 @@ _(Autotrim)_:
</div>
<?if (isPool($name)):?>
_(Enable user share assignment)_:
<?$disabled = _var($var,'fsState')!="Stopped" ? "disabled" : ""?>
: <select id="shareEnabled" name="diskShareEnabled.<?=_var($disk,'idx',0)?>" onchange="freeSpace(this.value)" <?=$disabled?>>
: <select id="shareEnabled" name="diskShareEnabled.<?=_var($disk,'idx',0)?>" onchange="freeSpace(this.value)" <?=disabled_if(_var($var,'fsState')!="Stopped")?>>
<?=mk_option(_var($disk,'shareEnabled'), "yes", _('Yes'))?>
<?=mk_option(_var($disk,'shareEnabled'), "no", _('No'))?>
</select>

View File

@@ -92,9 +92,31 @@ refresh(); // automatically include new ethernet ports
Array.prototype.same = function(){return this.sort().filter(function(v,i,o){return i&&v===o[i-1]?v:0;}).length;}
function prepareSettings(form) {
var metrics = [];
var metrics6 = [];
var bondnics = [], brnics = [];
for (var i=0,nic; nic=form.BONDNICS.options[i]; i++) {
if (nic.selected) {
bondnics.push(nic.value);
nic.selected = false;
}
}
nic = form.BONDNICS.options[0];
nic.value = bondnics.join(',');
nic.selected = true;
nic.disabled = false;
for (var i=0,nic; nic=form.BRNICS.options[i]; i++) {
if (nic.selected) {
brnics.push(nic.value);
nic.selected = false;
}
}
nic = form.BRNICS.options[0];
nic.value = form.BONDING.value=='yes' ? form.BONDNAME.value : brnics.join(',');
nic.selected = true;
nic.disabled = false;
if (brnics.length>1) form.BRSTP.value = 'yes';
if ($(form).find('input[name="#arg[1]"]').val()=='none') return true;
var metrics = [], metrics6 = [];
$(form).find('input[name^="METRIC:"]').each(function(){if($(this).val()>0) metrics.push($(this).val());});
$(form).find('input[name^="METRIC6:"]').each(function(){if($(this).val()>0) metrics6.push($(this).val());});
if (metrics.same() || metrics6.same()) {
@@ -123,31 +145,6 @@ function prepareSettings(form) {
return false;
}
}
var member = '';
for (var i=0,item; item=form.BONDNICS.options[i]; i++) {
if (item.selected) {
if (member.length) member += ',';
member += item.value;
item.selected = false;
}
}
item = form.BONDNICS.options[0];
item.value = member;
item.selected = true;
item.disabled = false;
var member = '';
for (var i=0,item; item=form.BRNICS.options[i]; i++) {
if (item.selected) {
if (member.length) member += ',';
member += item.value;
item.selected = false;
}
}
item = form.BRNICS.options[0];
item.value = form.BONDING.value=='yes' ? form.BONDNAME.value : member;
item.selected = true;
item.disabled = false;
if (member.indexOf(',')>0) form.BRSTP.value = 'yes';
$(form).find('select[name^="PROTOCOL:"]').each(function() {
var protocol = $(this).val() || 'ipv4';
var i = $(this).attr('name').split(':')[1];

View File

@@ -5,8 +5,8 @@ Icon="icon-key"
Tag="expeditedssl"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -56,7 +56,7 @@ $nginx = @parse_ini_file('/var/local/emhttp/nginx.ini') ?: [];
$addr = _var($nginx,'NGINX_LANIP') ?: _var($nginx,'NGINX_LANIP6');
$keyfile = empty(_var($var,'regFILE')) ? false : @file_get_contents(_var($var,'regFILE'));
$cert2Issuer = '';
$isLEcert = false;
$isWildcardCert = false;
if ($keyfile !== false) $keyfile = base64_encode($keyfile);
// self-signed or user-provided cert
@@ -75,32 +75,27 @@ if ($cert1Present) {
$cert1SelfSigned = ($cert1Subject == $cert1Issuer);
}
// unraid.net, myunraid.net LE cert. could potentially be user provided as well
// myunraid.net LE cert. could potentially be user provided as well
$cert2File = "/boot/config/ssl/certs/certificate_bundle.pem";
$cert2Present = file_exists("$cert2File");
if ($cert2Present) {
$cert2Subject = exec("/usr/bin/openssl x509 -in $cert2File -noout -subject -nameopt multiline 2>/dev/null|sed -n 's/ *commonName *= //p'");
$cert2Issuer = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Issuer: //p'");
$cert2Expires = exec("/usr/bin/openssl x509 -in $cert2File -noout -text | sed -n -e 's/^.*Not After : //p'");
$isLegacyCert = preg_match('/.*\.unraid\.net$/', $cert2Subject);
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', $cert2Subject);
$isLEcert = $isLegacyCert || $isWildcardCert;
$subject2URL = $cert2Subject;
$dnsValid = false;
$dnsRebindingProtection = false;
if ($isWildcardCert) {
if (!$addr)
// if eth0 doesn't have an IP address, then show noip.hash.myunraid.net as a placeholder url
$subject2URL = str_replace("*", 'noip', $subject2URL);
elseif (strpos($addr, ":") === false)
$subject2URL = str_replace("*", str_replace(".", "-", $addr), $subject2URL);
else
$subject2URL = str_replace("*", str_replace(":", "-", $addr), $subject2URL);
}
if ($isLEcert) {
exec("openssl x509 -checkend 2592000 -noout -in $cert2File 2>/dev/null", $arrout, $retval_expired);
if (!$addr) {
// if eth0 doesn't have an IP address, then show noip.hash.myunraid.net as a placeholder url
$subject2URL = str_replace("*", 'noip', $subject2URL);
$dnsValid = false;
$dnsRebindingProtection = false;
} elseif (strpos($addr, ":") === false) {
// eth0 is IPv4
$subject2URL = str_replace("*", str_replace(".", "-", $addr), $subject2URL);
$rebindtest_ip = exec("host -4 -t A rebindtest4.myunraid.net 2>/dev/null|awk '{print \$4}'");
$dnsRebindingProtection = ($rebindtest_ip != "192.168.42.42");
if (!$dnsRebindingProtection) {
@@ -108,6 +103,8 @@ if ($cert2Present) {
$dnsValid = $cert_ip==$addr;
}
} else {
// eth0 is IPv6
$subject2URL = str_replace("*", str_replace(":", "-", $addr), $subject2URL);
$rebindtest_ip = exec("host -6 -t AAAA rebindtest6.myunraid.net 2>/dev/null|awk '{print \$4}'");
// more: restore this after TTL expires
// $dnsRebindingProtection = ($rebindtest_ip != "fd42::42");
@@ -120,12 +117,12 @@ if ($cert2Present) {
}
}
$http_port = _var($var,'PORT',80) != 80 ? ":{$var['PORT']}" : '';
$https_port = _var($var,'PORTSSL',443) != 443 ? ":{$var['PORTSSL']}" : '';
$http_port = _var($var,'PORT','80') != '80' ? ":{$var['PORT']}" : '';
$https_port = _var($var,'PORTSSL','443') != '443' ? ":{$var['PORTSSL']}" : '';
$http_ip_url = "http://"._var($nginx,'NGINX_LANIP')."{$http_port}/";
$https_ip_url = "https://"._var($nginx,'NGINX_LANIP')."{$https_port}/";
$http_ip6_url = "http://"._var($nginx,'NGINX_LANIP6')."{$http_port}/";
$https_ip6_url = "https://"._var($nginx,'NGINX_LANIP6')."{$https_port}/";
$http_ip6_url = "http://["._var($nginx,'NGINX_LANIP6')."]{$http_port}/";
$https_ip6_url = "https://["._var($nginx,'NGINX_LANIP6')."]{$https_port}/";
$http_mdns_url = "http://"._var($nginx,'NGINX_LANMDNS')."{$http_port}/";
$https_mdns_url = "https://"._var($nginx,'NGINX_LANMDNS')."{$https_port}/";
$https_fqdn_url = "https://"._var($nginx,'NGINX_LANFQDN')."{$https_port}/";
@@ -166,14 +163,11 @@ case 'auto': // aka strict
}
$cert_time_format = $display['date'].($display['date']!='%c' ? ', '.str_replace(['%M','%R'],['%M:%S','%R:%S'],$display['time']):'');
$provisionlabel = $isLEcert ? _('Renew') : _('Provision');
$disabled_provision = $keyfile===false || ($isLEcert && $retval_expired===0) || !$addr ? 'disabled' : '';
$provisionlabel = $isWildcardCert ? _('Renew') : _('Provision');
$disabled_provision = $keyfile===false || ($isWildcardCert && $retval_expired===0) || !$addr ? 'disabled' : '';
$disabled_provision_msg = !$addr ? _('Ensure the primary network card eth0 has an IP address.') : '';
$disabled_upgrade = !$addr ? 'disabled' : '';
$disabled_updatedns = $keyfile!==false && $isLEcert ? '' : 'disabled';
$disabled_delete = $cert2Present && $var['USE_SSL']!='auto' ? '' : 'disabled';
$disabled_auto = $isLEcert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled';
$upgradelabel = _('Upgrade Cert');
$disabled_auto = $isWildcardCert && !$dnsRebindingProtection && $dnsValid ? '' : 'disabled';
// Get ports in use
$portsInUse = [];
@@ -200,23 +194,6 @@ function provisionHandler(event, form) { // provisions and renewals require bein
if (event.submitter.value === 'Renew') return true; // always allow renewals
};
function updateDNS(button) {
$(button).prop("disabled", true).html("<i class='fa fa-circle-o-notch fa-spin fa-fw'></i>_(Update DNS)_");
var failure = function(data) {
var status = data.status;
var obj = data.responseJSON;
var msg = "_(Sorry, an error occurred updating unraid.net DNS records)_. _(The error is)_: "+obj.error+".";
$(button).prop("disabled", false).html("_(Update DNS)_");
swal({title:"_(Oops)_",text:msg,type:"error",html:true,confirmButtonText:"_(Ok)_"});
};
var success = function(data) {
$(button).prop("disabled", false).html("_(Update DNS)_");
<?$text = _('Your local IP address %s has been updated for unraid.net')?>
swal({title:"",text:"<?=sprintf($text,$addr)?>",type:"success",html:true,confirmButtonText:"_(Ok)_"});
};
$.post("/webGui/include/UpdateDNS.php",success).fail(failure);
}
function checkPorts(form) {
var portsInUse = [<?=implode(',',$portsInUse)?>];
var range = [], list = [], duplicates = [];
@@ -370,12 +347,10 @@ _(Local access URLs)_:
$n = 0;
foreach($urls as $url) {
$msg = "";
$url0 = substr_count($url[0]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[0]) : $url[0]; // IPv6 - IPv4 notation
$url1 = substr_count($url[1]??'',':')>3 ? preg_replace('#(://)(.+?)(:?\d*)/$#','$1[$2]$3/',$url[1]) : $url[1]; // IPv6 - IPv4 notation
if ($url[1]) $msg .= " "._("redirects to")." <a href='$url1'>$url1</a>";
if ($url[1]) $msg .= " "._("redirects to")." <a href='$url[1]'>$url[1]</a>";
if ($url[2]) $msg .= " "._("uses")." ".$url[2];
if ($url[3]) $msg .= "<span class='warning'> <i class='fa fa-warning fa-fw'></i> "._("is a self-signed certificate, ignore the browser's warning and proceed to the GUI")."</span>";
echo ($n ? "<dt>&nbsp;</dt><dd>" : ""),"<a href='$url0'>$url0</a>$msg",($n++ ? "</dd>" : "");
echo ($n ? "<dt>&nbsp;</dt><dd>" : ""),"<a href='$url[0]'>$url[0]</a>$msg",($n++ ? "</dd>" : "");
}?>
:mgmt_local_access_urls_help:
@@ -442,12 +417,7 @@ _(CA-signed certificate file)_:
<?endif;?>
&nbsp;
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><!-- <button type="button" onclick="updateDNS(this)" <?=$disabled_updatedns?>>_(Update DNS)_</button> --><?=$disabled_provision_msg?>
<?if ($cert2Present && $isLegacyCert):?>
&nbsp;
: <button type="submit" name="changePorts" value="Upgrade" <?=$disabled_upgrade?>><?=$upgradelabel?></button>
<?endif;?>
: <button type="submit" name="changePorts" value="Provision" <?=$disabled_provision?>><?=$provisionlabel?></button><button type="submit" name="changePorts" value="Delete" <?=$disabled_delete?> >_(Delete)_</button><?=$disabled_provision_msg?>
:mgmt_certificate_expiration_help:

View File

@@ -225,7 +225,6 @@ function readSMB() {
$.get('/webGui/include/ProtocolData.php',{protocol:'smb',name:name},function(json) {
var data = $.parseJSON(json);
form.shareExport.value = data.export;
form.shareFruit.value = data.fruit;
form.shareSecurity.value = data.security;
});
$(form).find('select').trigger('change');
@@ -245,7 +244,6 @@ function writeSMB(data,n,i) {
data[i] = {};
data[i]['shareName'] = $(this).val();
data[i]['shareExport'] = '<?=addslashes(htmlspecialchars($sec[$name]['export']))?>';
data[i]['shareFruit'] = '<?=addslashes(htmlspecialchars($sec[$name]['fruit']))?>';
data[i]['shareSecurity'] = '<?=addslashes(htmlspecialchars($sec[$name]['security']))?>';
data[i]['changeShareSecurity'] = 'Apply';
i++;

View File

@@ -158,7 +158,7 @@ function textsave(module,remove = false) {
if (data.modprobe == "") $('#text'+module).attr('hidden', true); else $('#text'+module).attr('rows', 3);
if (data.supportpage == true) {
if (data.support == true) {
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='" + _("Support page")_ + "' class='fa fa-phone-square'></i></a>" ;
document.getElementById("link" + module).innerHTML = "<a href='" + data.supporturl + "'target='_blank'><i title='" + "_(Support page)_" + "' class='fa fa-phone-square'></i></a>" ;
}
}
}

View File

@@ -18,19 +18,28 @@ Tag="list"
<?
$zip = htmlspecialchars(str_replace(' ','_',strtolower($var['NAME'])));
$log = '/var/log/syslog';
$prev = '/boot/logs/syslog-previous';
$cfg = '/boot/config/rsyslog.cfg';
$max = 5000;
$select = [];
$logs = [];
if (file_exists($cfg)) {
$syslog = parse_ini_file($cfg);
if (isset($syslog['local_server']) && isset($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
if (!empty($syslog['local_server']) && !empty($syslog['server_folder']) && $logs = glob($syslog['server_folder'].'/syslog-*.log',GLOB_NOSORT)) {
natsort($logs);
$select[] = "<select onchange='showLog(this.value)'>";
$select[] = mk_option(1,$log,'syslog');
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
$select[] = "</select>";
}
}
if (file_exists($prev)) {
// add syslog-previous to front of logs array
array_unshift($logs, $prev);
}
if (count($logs)) {
// add syslog to front of logs array
array_unshift($logs, $log);
$select[] = "<select onchange='showLog(this.value)'>";
foreach ($logs as $file) $select[] = mk_option(1,$file,basename($file));
$select[] = "</select>";
}
$select = implode($select);
?>
<style>

View File

@@ -166,6 +166,14 @@ _(Mirror syslog to flash)_:
:syslog_mirror_flash_help:
_(Copy syslog to flash on shutdown)_:
: <select name="syslog_shutdown">
<?=mk_option(_var($syslog,'syslog_shutdown'), "", _("Yes"))?>
<?=mk_option(_var($syslog,'syslog_shutdown'), "1", _("No"))?>
</select>
:syslog_shutdown_flash_help:
&nbsp;
: <input type="button" value="_(Apply)_" onclick='validatePort(this.form)' disabled><input type="button" value="_(Done)_" onclick="done()">
</form>

View File

@@ -138,21 +138,22 @@ $server = ipaddr($ethX);
$dnsserver = _var($$ethX,'DNS_SERVER1');
$link = iflink($ethX);
$vhost = str_replace(['eth','br','bond'],'vhost',$link);
$postUp0 = "$script add $link WireGuard-<wg> $server <port> <port> udp";
$postUp1 = "logger -t wireguard 'Tunnel WireGuard-<wg> started';$services";
$postUp2 = "iptables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE";
$postUp2 = "iptables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE;iptables -t nat -A POSTROUTING -s <source> -o $vhost -j MASQUERADE";
$postUp3 = "iptables -N WIREGUARD_DROP_<WG>;iptables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
$postUpX = "iptables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
$postUpZ = "iptables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT;iptables -A WIREGUARD_DROP_<WG> -j RETURN";
$postUp26 = "ip6tables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE";
$postUp26 = "ip6tables -t nat -A POSTROUTING -s <source> -o $link -j MASQUERADE;ip6tables -t nat -A POSTROUTING -s <source> -o $vhost -j MASQUERADE";
$postUp36 = "ip6tables -N WIREGUARD_DROP_<WG>;ip6tables -A WIREGUARD -o $link -j WIREGUARD_DROP_<WG>";
$postUpX6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -d <target> -j DROP";
$postUpZ6 = "ip6tables -A WIREGUARD_DROP_<WG> -s <source> -j ACCEPT;ip6tables -A WIREGUARD_DROP_<WG> -j RETURN";
$postDown0 = "$script del $link <port> udp";
$postDown1 = "logger -t wireguard 'Tunnel WireGuard-<wg> stopped';$services";
$postDown2 = "iptables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
$postDown2 = "iptables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE;iptables -t nat -D POSTROUTING -s <source> -o $vhost -j MASQUERADE";
$postDown3 = "iptables -F WIREGUARD_DROP_<WG>;iptables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>;iptables -X WIREGUARD_DROP_<WG>";
$postDown26= "ip6tables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE";
$postDown26= "ip6tables -t nat -D POSTROUTING -s <source> -o $link -j MASQUERADE;ip6tables -t nat -D POSTROUTING -s <source> -o $vhost -j MASQUERADE";
$postDown36= "ip6tables -F WIREGUARD_DROP_<WG>;ip6tables -D WIREGUARD -o $link -j WIREGUARD_DROP_<WG>;ip6tables -X WIREGUARD_DROP_<WG>";
$tld = @file_get_contents("$docroot/webGui/include/tld.key")?:'';
@@ -252,7 +253,7 @@ refresh();
Number.prototype.long2ip = function(){return [this>>>24,this>>>16&255,this>>>8&255,this&255].join('.');}
String.prototype.ip2long = function(){var ip=this.split('.');return (ip[0]<<24)+(ip[1]<<16)+(ip[2]<<8)+(ip[3]*1);}
String.prototype.desc = function(){return this.substr(this.lastIndexOf('/'));}
String.prototype.patch = function(s,t){return t?this.replace(/<source>/,s).replace(/<target>/,t):this.replace(/<source>/,s);}
String.prototype.patch = function(s,t){return t?this.replace(/<source>/g,s).replace(/<target>/,t):this.replace(/<source>/g,s);}
Array.prototype.bind = function(w){return (this.join(';')).replace(/<WG>/g,w).replace(/,/g,';');}
var xml = $.cookie('upnp')||'<?=@file_get_contents('/var/tmp/upnp')?>';

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

View File

@@ -9,8 +9,8 @@ if (!empty($_COOKIE['unraid_'.md5($server_name)])) {
// Check if the user is already logged in
if ($_SESSION && !empty($_SESSION['unraid_user'])) {
// If so redirect them to the start page
header("Location: /".$var['START_PAGE']);
// Redirect the user to the start page
header("Location: /".$start_page);
exit;
}
}
@@ -219,7 +219,7 @@ if (!empty($username) && !empty($password)) {
exec("logger -t webGUI ".escapeshellarg("Successful login user {$username} from {$remote_addr}"));
// Redirect the user to the start page
header("Location: /".$var['START_PAGE']);
header("Location: /".$start_page);
exit;
} catch (Exception $exception) {
// Set error message

View File

@@ -30,7 +30,8 @@ if (!empty($_POST['password']) && !empty($_POST['confirmPassword'])) {
session_regenerate_id(true);
session_write_close();
header("Location: /".$var['START_PAGE']);
// Redirect the user to the start page
header("Location: /".$start_page);
exit;
}

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -383,6 +383,12 @@ function openDone(data) {
if (data == '_DONE_') {
$('div.spinner.fixed').hide();
$('button.confirm').text("<?=_('Done')?>").prop('disabled',false).show();
if ( typeof ca_done_override !== 'undefined' ) {
if (ca_done_override == true) {
$("button.confirm").trigger("click");
ca_done_override = false;
}
}
return true;
}
return false;
@@ -595,7 +601,7 @@ $.ajaxPrefilter(function(s, orig, xhr){
<div id="header" class="<?=$display['banner']?>">
<div class="logo">
<a href="https://unraid.net" target="_blank"><?readfile("$docroot/webGui/images/UN-logotype-gradient.svg")?></a>
<?=_('Version')?>: <?=_var($var,'version','?')?><?=$notes?>
<unraid-i18n-host><unraid-header-os-version></unraid-header-os-version></unraid-i18n-host>
</div>
<?include "$docroot/plugins/dynamix.my.servers/include/myservers2.php"?>
</div>
@@ -751,7 +757,7 @@ default:
echo "<span class='green strong'><i class='fa fa-play-circle'></i> "._('Array Started')."</span>$progress"; break;
}
echo "</span></span><span id='countdown'></span><span id='user-notice' class='red-text'></span>";
echo "<span id='copyright'>Unraid&reg; webGui &copy;2023, Lime Technology, Inc.";
echo "<span id='copyright'>Unraid&reg; webGui &copy;2024, Lime Technology, Inc.";
echo " <a href='https://docs.unraid.net/category/manual' target='_blank' title=\""._('Online manual')."\"><i class='fa fa-book'></i> "._('manual')."</a>";
echo "</span></div>";
?>
@@ -980,14 +986,6 @@ $(function() {
<?if ($safemode):?>
showNotice("<?=_('System running in')?> <b><?=('safe mode')?></b>");
<?else:?>
<?$readme = @file_get_contents("$docroot/plugins/unRAIDServer/README.md",false,null,0,20)?:''?>
<?if (strpos($readme,'REBOOT REQUIRED')!==false):?>
showUpgrade("<b><?=_('Reboot Now')?></b> <?=_('to upgrade Unraid OS')?>",true);
<?elseif (strpos($readme,'DOWNGRADE')!==false):?>
showUpgrade("<b><?=_('Reboot Now')?></b> <?=_('to downgrade Unraid OS')?>",true);
<?elseif ($version = plugin_update_available('unRAIDServer',true)):?>
showUpgrade("Unraid OS v<?=$version?> <?=_('is available')?>. <?if (is_file('/tmp/plugins/unRAIDServer.txt')):?><span class='fa fa-info-circle fa-fw big blue-text' onclick='showUpgradeChanges()' title=\"<?=_('Release Notes')?>\"></span> <?endif;?><a><?=_('Update Now')?></a>");
<?endif;?>
<?if (!_var($notify,'system')):?>
addBannerWarning("<?=_('System notifications are')?> <b><?=_('disabled')?></b>. <?=_('Click')?> <a href='/Settings/Notifications'><?=_('here')?></a> <?=_('to change notification settings')?>.",true,true);
<?endif;?>

View File

@@ -88,7 +88,7 @@ foreach ($disks as $name => $disk) {
} else $luks = "";
echo "<tr><td><a class='view' href=\"/$path/Browse?dir=/mnt/$name\"><i class=\"icon-u-tab\" title=\"",_('Browse')," /mnt/$name\"></i></a>";
echo "<a class='info nohand' onclick='return false'><i class='fa fa-$orb orb $color-orb'></i><span style='left:18px'>$help</span></a>$luks<a href=\"/$path/Disk?name=$name\" onclick=\"$.cookie('one','tab1')\">",compress($name),"</a></td>";
echo "<td>{$disk['comment']}</td>";
echo "<td>"._var($disk,'comment')."</td>";
echo "<td>",disk_share_settings(_var($var,'shareSMBEnabled'), $sec[$name]),"</td>";
echo "<td>",disk_share_settings(_var($var,'shareNFSEnabled'), $sec_nfs[$name]),"</td>";
$cmd="/webGui/scripts/disk_size&arg1=$name&arg2=ssz2";

View File

@@ -14,7 +14,7 @@ $docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
if (array_key_exists('getdiagnostics', $_GET)) {
$anonymize = empty($_GET['anonymize']) ? '-a' : '';
$diag_file = '/tmp/feedback_diagnostics_'.time().'.zip';
$diag_file = '/tmp/feedback-diagnostics-'.date('Ymd-Hi').'.zip';
exec("$docroot/webGui/scripts/diagnostics $anonymize $diag_file");
echo base64_encode(@file_get_contents($diag_file));
@unlink($diag_file);

View File

@@ -1,4 +1,4 @@
<?PHP
<?php
/* Copyright 2005-2023, Lime Technology
*
* This program is free software; you can redistribute it and/or
@@ -8,57 +8,76 @@
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
$docroot = ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Helpers.php";
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
require_once "$docroot/webGui/include/Translations.php";
/**
* @name response_complete
* @param {HTTP Response Status Code} $httpcode https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
* @param {String|Array} $result - strings are assumed to be encoded JSON. Arrays will be encoded to JSON.
* @param {String} $cli_success_msg
*/
class KeyInstaller
{
private $isGetRequest;
private $getHasUrlParam;
function response_complete($httpcode, $result, $cli_success_msg='') {
global $cli;
$mutatedResult = is_array($result) ? json_encode($result) : $result;
if ($cli) {
$json = @json_decode($mutatedResult,true);
if (!empty($json['error'])) {
echo 'Error: '.$json['error'].PHP_EOL;
exit(1);
public function __construct()
{
$this->isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
$this->getHasUrlParam = $_GET !== null && !empty($_GET) && isset($_GET['url']);
if ($this->isGetRequest && $this->getHasUrlParam) {
$this->installKey();
}
}
/**
* @param int $httpcode https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
* @param string|array $result - strings are assumed to be encoded JSON. Arrays will be encoded to JSON.
*/
private function responseComplete($httpcode, $result)
{
$mutatedResult = is_array($result) ? json_encode($result) : $result;
if ($this->isGetRequest && $this->getHasUrlParam) { // return JSON to the caller
header('Content-Type: application/json');
http_response_code($httpcode);
exit((string)$mutatedResult);
} else { // return the result to the caller
return $mutatedResult;
}
}
public function installKey($keyUrl = null)
{
$url = unscript($keyUrl ?? _var($_GET, 'url'));
$host = parse_url($url)['host'] ?? '';
if (!function_exists('_')) {
function _($text) {return $text;}
}
if ($host && in_array($host, ['keys.lime-technology.com', 'lime-technology.com'])) {
$keyFile = basename($url);
exec("/usr/bin/wget -q -O " . escapeshellarg("/boot/config/$keyFile") . " " . escapeshellarg($url), $output, $returnVar);
if ($returnVar === 0) {
$var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
if (_var($var, 'mdState') == "STARTED") {
return $this->responseComplete(200, ['status' => _('Please Stop array to complete key installation')], _('success') . ', ' . _('Please Stop array to complete key installation'));;
} else {
return $this->responseComplete(200, ['status' => ''], _('success'));;
}
} else {
return $this->responseComplete(406, ['error' => _('download error') . " $returnVar"]);;
}
} else {
return $this->responseComplete(406, ['error' => _('bad or missing key file') . ": $url"]);;
}
}
exit($cli_success_msg.PHP_EOL);
}
header('Content-Type: application/json');
http_response_code($httpcode);
exit((string)$mutatedResult);
}
$cli = php_sapi_name()=='cli';
$url = unscript(_var($_GET,'url'));
$host = parse_url($url)['host']??'';
$isGetRequest = !empty($_SERVER) && isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET';
$getHasUrlParam = $_GET !== null && !empty($_GET) && isset($_GET['url']);
if ($host && in_array($host,['keys.lime-technology.com','lime-technology.com'])) {
$key_file = basename($url);
exec("/usr/bin/wget -q -O ".escapeshellarg("/boot/config/$key_file")." ".escapeshellarg($url), $output, $return_var);
if ($return_var === 0) {
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
if (_var($var,'mdState')=="STARTED") {
response_complete(200, array('status' => _('Please Stop array to complete key installation')), _('success').', '._('Please Stop array to complete key installation'));
} else {
response_complete(200, array('status' => ''), _('success'));
}
} else {
response_complete(406, array('error' => _('download error') . " $return_var"));
}
} else {
response_complete(406, array('error' => _('bad or missing key file') . ": $url"));
if ($isGetRequest && $getHasUrlParam) {
$keyInstaller = new KeyInstaller();
$keyInstaller->installKey();
}
?>

View File

@@ -287,6 +287,47 @@ done
]]>
</Script>
</Agent>
<Agent>
<Name>ntfy.sh</Name>
<Variables>
<Variable Help="The full server base URL including protocol and port. eg: https://ntfy.sh" Desc="Full Server Base URL" Default="FULL NTFY.SH URL">SERVER_URL</Variable>
<Variable Help="The ntfy.sh Token to use." Desc="ntfy.sh Token" Default="YOUR NTFY.SH TOKEN">NTFY_TOKEN</Variable>
<Variable Help="The ntfy.sh Topic to use." Desc="ntfy.sh Topic" Default="Unraid">TOPIC</Variable>
<Variable Help="Specify the fields which are included in the title of the notification." Desc="Notification Title" Default="$SUBJECT">TITLE</Variable>
<Variable Help="Specify the fields which are included in the message body of the notification." Desc="Notification Message" Default="$DESCRIPTION">MESSAGE</Variable>
</Variables>
<Script>
<![CDATA[
#!/bin/bash
############
{0}
############
MESSAGE=$(echo -e "$MESSAGE")
case "$IMPORTANCE" in
'normal' )
PRIORITY="default"
;;
'warning' )
PRIORITY="high"
;;
'alert' )
PRIORITY="urgent"
;;
esac
# Remove any trailing slash
SERVER_URL=${SERVER_URL%/}
curl \
-H "Priority: $PRIORITY" \
-H "Icon: https://raw.githubusercontent.com/unraid/webgui/master/emhttp/plugins/dynamix.vm.manager/templates/images/unraid.png" \
-H "Authorization: Bearer $NTFY_TOKEN" \
-H "Title: $TITLE" \
-d "$MESSAGE" \
$SERVER_URL/$TOPIC
]]>
</Script>
</Agent>
<Agent>
<Name>Prowl</Name>
<Variables>

View File

@@ -38,13 +38,13 @@ foreach ($files as $file) {
$c = 0;
foreach ($fields as $field) {
if ($c==5) break;
$text = $field ? explode('=',$field,2)[1] : "-";
$text = $field ? (explode('=',$field,2)[1]??"") : "-";
$tag = ($c<4) ? "" : " data='".str_replace(['alert','warning','normal'],['0','1','2'],$text)."'";
echo (!$c++) ? "<tr>".str_replace('*',$text,$td_).date($dynamix['notify']['date'].' '.$dynamix['notify']['time'],$text)."$_td" : "<td$tag>"._($text)."</td>";
}
echo "<td><a href='#' onclick='$(this).hide();$.post(\"/webGui/include/DeleteLogFile.php\",{log:\"$archive\"},function(){archiveList();});return false' title=\""._('Delete notification')."\"><i class='fa fa-trash-o'></i></a></td></tr>";
if ($extra) {
$text = explode('=',$field,2)[1];
$text = explode('=',$field,2)[1]??"";
echo "<tr class='tablesorter-childRow row$row'><td colspan='4'>$text</td><td></td></tr><tr class='tablesorter-childRow row$row'><td colspan='5'></td></tr>";
$row++;
}

View File

@@ -46,9 +46,8 @@ $certPresent = file_exists($certPath);
if ($certPresent) {
// renew existing cert
$certSubject = exec("/usr/bin/openssl x509 -subject -noout -in ".escapeshellarg($certPath));
$isLegacyCert = preg_match('/.*\.unraid\.net$/', $certSubject);
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', $certSubject);
if ($isLegacyCert || $isWildcardCert) {
if ($isWildcardCert) {
exec("/usr/bin/openssl x509 -checkend 2592000 -noout -in ".escapeshellarg($certPath), $arrout, $retval_expired);
if ($retval_expired === 0) {
// not within 30 days of cert expire date
@@ -59,7 +58,6 @@ if ($certPresent) {
response_complete(406, '{"error":"'._('Cannot renew a custom cert at').' '.$certPath.'"}');
}
}
$endpoint = ($certPresent && $isLegacyCert) ? "provisioncert" : "provisionwildcard";
$keyfile = empty($var['regFILE']) ? false : @file_get_contents($var['regFILE']);
if ($keyfile === false) {
@@ -67,7 +65,7 @@ if ($keyfile === false) {
}
$keyfile = @base64_encode($keyfile);
$ch = curl_init("https://keys.lime-technology.com/account/ssl/$endpoint");
$ch = curl_init("https://keys.lime-technology.com/account/ssl/provisionwildcard");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, [

View File

@@ -1,85 +1,196 @@
<?PHP
/* Copyright 2005-2020, Lime Technology
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
?>
<?
<?php
$webguiGlobals = $GLOBALS;
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = 'tools';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Helpers.php";
extract(parse_plugin_cfg('dynamix',true));
class ReplaceKey
{
private const KEY_SERVER_URL = 'https://keys.lime-technology.com';
$var = parse_ini_file('state/var.ini');
$keyfile = base64_encode(file_get_contents($var['regFILE']));
?>
<!DOCTYPE html>
<html <?=$display['rtl']?>lang="<?=strtok($locale,'_')?:'en'?>">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Security-Policy" content="block-all-mixed-content">
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=1300">
<meta name="robots" content="noindex, nofollow">
<meta name="referrer" content="same-origin">
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-fonts.css")?>">
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/default-popup.css")?>">
<script src="<?autov('/webGui/javascript/dynamix.js')?>"></script>
<script>
function replaceKey(email, guid, keyfile) {
if (email.length) {
var timestamp = <?=time()?>;
$('#status_panel').slideUp('fast');
$('#input_form').find('input').prop('disabled', true);
// Nerds love spinners, Maybe place a spinner image next to the submit button; we'll show it now:
$('#spinner_image').fadeIn('fast');
private $docroot;
private $var;
private $guid;
private $keyfile;
private $regExp;
$.post('https://keys.lime-technology.com/account/license/transfer',{timestamp:timestamp,guid:guid,email:email,keyfile:keyfile},function(data) {
$('#spinner_image').fadeOut('fast');
var msg = "<p><?=_('A registration replacement key has been created for USB Flash GUID')?> <strong>"+guid+"</strong></p>" +
"<p><?=_('An email has been sent to')?> <strong>"+email+"</strong> <?=_('containing your key file URL')?>." +
" <?=_('When received, please paste the URL into the *Key file URL* box and')?>" +
" <?=_('click <i>Install Key</i>')?>.</p>" +
"<p><?=_('If you do not receive an email, please check your spam or junk-email folder')?>.</p>";
public function __construct()
{
$this->docroot = $GLOBALS['docroot'] ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
$('#status_panel').hide().html(msg).slideDown('fast');
$('#input_form').fadeOut('fast');
}).fail(function(data) {
$('#input_form').find('input').prop('disabled', false);
$('#spinner_image').fadeOut('fast');
var status = data.status;
var obj = data.responseJSON;
var msg = "<p><?=_('Sorry, an error occurred')?> <?=_('registering USB Flash GUID')?> <strong>"+guid+"</strong><p>"+"<p><?=_('The error is')?>: "+obj.error+"</p>";
$this->var = (array)@parse_ini_file('/var/local/emhttp/var.ini');
$this->guid = @$this->var['regGUID'] ?? null;
$('#status_panel').hide().html(msg).slideDown('fast');
});
}
$keyfileBase64 = empty($this->var['regFILE']) ? null : @file_get_contents($this->var['regFILE']);
if ($keyfileBase64 !== false) {
$keyfileBase64 = @base64_encode($keyfileBase64);
$this->keyfile = str_replace(['+', '/', '='], ['-', '_', ''], trim($keyfileBase64));
}
$this->regExp = @$this->var['regExp'] ?? null;
}
private function request($url, $method, $payload = null, $headers = null)
{
$ch = curl_init($url);
// Set the request method
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
// store the response in a variable instead of printing it
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Set the payload if present
if ($payload !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
}
if ($headers !== null) {
// Set the headers
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
// Set additional options as needed
// Execute the request
$response = curl_exec($ch);
// Check for errors
if (curl_errno($ch)) {
$error = [
'heading' => 'CurlError',
'message' => curl_error($ch),
'level' => 'error',
'ref' => 'curlError',
'type' => 'request',
];
// @todo store error
}
// Close the cURL session
curl_close($ch);
return $response;
}
private function validateGuid()
{
$headers = [
'Content-Type: application/x-www-form-urlencoded',
];
$params = [
'guid' => $this->guid,
'keyfile' => $this->keyfile,
];
/**
* returns {JSON}
* hasNewerKeyfile : boolean;
* purchaseable: true;
* registered: false;
* replaceable: false;
* upgradeable: false;
* upgradeAllowed: string[];
* updatesRenewable: false;
*/
$response = $this->request(
self::KEY_SERVER_URL . '/validate/guid',
'POST',
http_build_query($params),
$headers,
);
// Handle the response as needed (parsing JSON, etc.)
$decodedResponse = json_decode($response, true);
if (!empty($decodedResponse)) {
return $decodedResponse;
}
// @todo save error response somewhere
return [];
}
private function getLatestKey()
{
$headers = [
'Content-Type: application/x-www-form-urlencoded',
];
$params = [
'keyfile' => $this->keyfile,
];
/**
* returns {JSON}
* license: string;
*/
$response = $this->request(
self::KEY_SERVER_URL . '/key/latest',
'POST',
http_build_query($params),
$headers,
);
// Handle the response as needed (parsing JSON, etc.)
$decodedResponse = json_decode($response, true);
if (!empty($decodedResponse) && !empty($decodedResponse['license'])) {
return $decodedResponse['license'];
}
return null;
}
private function installNewKey($key)
{
require_once "$this->docroot/webGui/include/InstallKey.php";
$KeyInstaller = new KeyInstaller();
$KeyInstaller->installKey($key);
}
private function writeJsonFile($file, $data)
{
if (!is_dir(dirname($file))) { // prevents errors when directory doesn't exist
mkdir(dirname($file));
}
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
}
public function check()
{
// we don't need to check
if (empty($this->guid) || empty($this->keyfile) || empty($this->regExp)) {
return;
}
// set $isAlreadyExpired to true if regExp is in the past
$isAlreadyExpired = $this->regExp <= time();
// if regExp is seven days or less from now, we need to check
$isWithinSevenDays = $this->regExp <= strtotime('+7 days');
$shouldCheck = $isAlreadyExpired || $isWithinSevenDays;
if (!$shouldCheck) {
return;
}
// see if we have a new key
$validateGuidResponse = $this->validateGuid();
$hasNewerKeyfile = @$validateGuidResponse['hasNewerKeyfile'] ?? false;
if (!$hasNewerKeyfile) {
return; // if there is no newer keyfile, we don't need to do anything
}
$latestKey = $this->getLatestKey();
if (!$latestKey) {
// we supposedly have a new key, but didn't get it back…
$this->writeJsonFile(
'/tmp/ReplaceKey/error.json',
[
'error' => 'Failed to retrieve latest key after getting a `hasNewerKeyfile` in the validation response.',
]
);
return;
}
$this->installNewKey($latestKey);
}
}
</script>
</head>
<body>
<div style="margin-top:20px;line-height:30px;margin-left:40px">
<div id="status_panel"></div>
<form markdown="1" id="input_form">
Email address: <input type="text" name="email" maxlength="1024" value="" style="width:33%">
<input type="button" value="Replace Key" onclick="replaceKey(this.form.email.value.trim(), '<?=$var['flashGUID']?>', '<?=$keyfile?>')">
<p>A link to your replacement key will be delivered to this email address.
<p><strong>Note:</strong>
Once a replacement key is generated, your old USB Flash device will be <b>blacklisted</b>.
</form>
</div>
</body>
</html>

View File

@@ -38,6 +38,9 @@ function duration(&$hrs) {
$age = date_diff($poh,$now);
$hrs = "$hrs (".($age->y?"{$age->y}y, ":"").($age->m?"{$age->m}m, ":"").($age->d?"{$age->d}d, ":"")."{$age->h}h)";
}
function blocks_size(&$blks,$blk_size) {
$blks = "$blks (".my_scale($blks*$blk_size,$unit)." $unit)";
}
function append(&$ref, &$info) {
if ($info) $ref .= ($ref ? " " : "").$info;
}
@@ -61,6 +64,7 @@ case "attributes":
$max = ($disk['maxTemp'] ?? $display['max'] ?? 0) ?: 0;
$hot = ($disk['hotTemp'] ?? $display['hot'] ?? 0) ?: 0;
$top = $_POST['top'] ?? 120;
$ssd_remaining = NULL;
$empty = true;
exec("smartctl -n standby -A $type ".escapeshellarg("/dev/$port"),$output);
// remove empty rows
@@ -82,6 +86,8 @@ case "attributes":
}
if ($info[8]=='-') $info[8] = 'Never';
if ($info[0]==9 && is_numeric(size($info[9]))) duration($info[9]);
if (str_starts_with($info[1], 'Total_LBAs_')) blocks_size($info[9],512); // Assumes 512 byte sectors
if (str_ends_with($info[1], '_32MiB')) blocks_size($info[9],32*1024*1024);
echo "<tr{$color}>".implode('',array_map('normalize', $info))."</tr>";
$empty = false;
}
@@ -100,11 +106,38 @@ case "attributes":
case 'Power on hours':
if (is_numeric(size($value))) duration($value);
break;
case 'Percentage used':
$ssd_remaining = 100 - str_replace('%', '', $value);
break;
}
if (str_ends_with($name, ', hours') && str_starts_with($value, 'minutes ')) {
$name = substr($name, 0, -7);
$value = substr($value, 8);
if (is_numeric(size($value))) duration($value);
}
echo "<tr{$color}><td>-</td><td>$name</td><td colspan='8'>$value</td></tr>";
$empty = false;
}
}
if (is_null($ssd_remaining)) {
// Try to look up SSD's 'Percentage Used Endurance Indicator' with special command
exec("smartctl -n standby -l ssd $type ".escapeshellarg("/dev/$port"), $ssd_out);
$ssd_out = array_filter($ssd_out);
foreach ($ssd_out as $row) {
if (str_ends_with($row, 'Percentage Used Endurance Indicator')) {
// Probably a SATA SSD
$info = explode(' ', trim(preg_replace('/\s+/',' ',$row)), 6);
$ssd_remaining = 100 - $info[3];
} elseif (str_starts_with($row, 'Percentage used endurance indicator:')) {
// Probably a SAS SSD
[$name,$value] = array_map('trim',explode(':', $row));
$ssd_remaining = 100 - str_replace('%','',$value);
}
}
}
if (!is_null($ssd_remaining)) {
echo "<tr><td>-</td><td>SSD endurance remaining</td><td colspan='8'>$ssd_remaining %</td></tr>";
}
if ($empty) echo "<tr><td colspan='10' style='text-align:center;padding-top:12px'>"._('Attributes not available')."</td></tr>";
break;
case "capabilities":
@@ -229,10 +262,10 @@ case "stop":
exec("smartctl -X $type ".escapeshellarg("/dev/$port"));
break;
case "update":
if ($disk["transport"] == "scsi") {
if ($disk["transport"] == "scsi" || $disk["transport"] == "nvme") {
$progress = exec("smartctl -n standby -l selftest $type ".escapeshellarg("/dev/$port")."|grep -Pom1 '\d+%'");
if ($progress) {
echo "<span class='big'><i class='fa fa-spinner fa-pulse'></i> "._('self-test in progress').", ".(100-substr($progress,0,-1))."% "._('complete')."</span>";
if ($disk["transport"] == "nvme") echo "<span class='big'><i class='fa fa-spinner fa-pulse'></i> "._('self-test in progress').", ".(substr($progress,0,-1))."% "._('complete')."</span>"; else echo "<span class='big'><i class='fa fa-spinner fa-pulse'></i> "._('self-test in progress').", ".(100-substr($progress,0,-1))."% "._('complete')."</span>";
break;
}
} else {

View File

@@ -76,7 +76,7 @@ switch ($_POST['table']) {
} else {
$supporturl = $module['supporturl'] ;
$pluginname = $module['plugin'] ;
$supporthtml = "<span id='link$modname'><a href='$supporturl' target='_blank'><i title='"._("Support page $pluginname")."' class='fa fa-phone-square'></i></a></span>" ;
$supporthtml = "<span id='link$modname'><a href='$supporturl' target='_blank'><i title='"._("Support page")." $pluginname' class='fa fa-phone-square'></i></a></span>" ;
}
}
$html .= "<td>$modname$supporthtml</td>" ;

View File

@@ -24,7 +24,7 @@ $lsmod = shell_exec("lsmod") ;
$supportpage = true;
$modtoplgfile = "/tmp/modulestoplg.json" ;
$sysdrvfile = "/tmp/sysdrivers.json" ;
$arrModtoPlg = json_decode(file_get_contents("/tmp/modulestoplg.json") ,TRUE) ;
$arrModtoPlg = file_exists($modtoplgfile) ? json_decode(file_get_contents($modtoplgfile), true) : '';
file_put_contents("/tmp/sysdrivers.init","1") ;
SysDriverslog("SysDrivers Build Starting") ;
modtoplg() ;

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -11,354 +11,16 @@
*/
?>
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
// add translations
$_SERVER['REQUEST_URI'] = 'settings';
require_once "$docroot/webGui/include/Translations.php";
require_once "$docroot/webGui/include/Helpers.php";
function host_lookup_ip($host) {
$result = @dns_get_record($host, DNS_A);
$ip = $result ? _var($result[0],'ip') : '';
return($ip);
}
function rebindDisabled() {
global $isLegacyCert;
$rebindtesturl = $isLegacyCert ? "rebindtest.unraid.net" : "rebindtest.myunraid.net";
// DNS Rebind Protection - this checks the server but clients could still have issues
$validResponse = ["192.168.42.42", "fd42"];
$response = host_lookup_ip($rebindtesturl);
return in_array(explode('::',$response)[0], $validResponse);
}
function format_port($port) {
return ($port != 80 && $port != 443) ? ':'.$port : '';
}
function anonymize_host($host) {
global $anon;
if ($anon) {
$host = preg_replace('/.*\.myunraid\.net/', '*.hash.myunraid.net', $host);
$host = preg_replace('/.*\.unraid\.net/', 'hash.unraid.net', $host);
}
return $host;
}
function anonymize_ip($ip) {
global $anon;
if ($anon && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
$ip = "[redacted]";
}
return $ip;
}
function generate_internal_host($host, $ip) {
if (strpos($host,'.myunraid.net') !== false) {
$host = str_replace('*', str_replace('.', '-', $ip), $host);
}
return $host;
}
function generate_external_host($host, $ip) {
if (strpos($host,'.myunraid.net') !== false) {
$host = str_replace('*', str_replace('.', '-', $ip), $host);
} elseif (strpos($host,'.unraid.net') !== false) {
$host = "www.".$host;
}
return $host;
}
function verbose_output($httpcode, $result) {
global $cli, $verbose, $anon, $plgversion, $post, $var, $isRegistered, $myservers, $reloadNginx, $nginx, $isLegacyCert;
global $remoteaccess;
global $icon_warn, $icon_ok;
if (!$cli || !$verbose) return;
if ($anon) echo "(Output is anonymized, use '-vv' to see full details)".PHP_EOL;
echo "Unraid OS "._var($var,'version','???').((strpos($plgversion, "base-") === false) ? " with My Servers plugin version {$plgversion}" : '').PHP_EOL;
echo ($isRegistered) ? "{$icon_ok}Signed in to Unraid.net as {$myservers['remote']['username']}".PHP_EOL : "{$icon_warn}Not signed in to Unraid.net".PHP_EOL ;
echo "Use SSL is "._var($nginx,'NGINX_USESSL','No').PHP_EOL;
echo (rebindDisabled()) ? "{$icon_ok}Rebind protection is disabled" : "{$icon_warn}Rebind protection is enabled";
echo " for ".($isLegacyCert ? "unraid.net" : "myunraid.net").PHP_EOL;
if ($post) {
$wanip = trim(@file_get_contents("https://wanip4.unraid.net/"));
// check the data
$certhostname = _var($nginx,'NGINX_CERTNAME');
if ($certhostname) {
// $certhostname is $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
$certhostip = host_lookup_ip(generate_internal_host($certhostname, _var($post,'internalip')));
$certhosterr = ($certhostip != _var($post,'internalip'));
}
if (_var($post,'internalhostname') != $certhostname) {
// $post['internalhostname'] is $nginx['NGINX_LANMDNS'] (no cert, or Server_unraid_bundle.pem) || $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
$internalhostip = host_lookup_ip(generate_internal_host(_var($post,'internalhostname'), _var($post,'internalip')));
$internalhosterr = ($internalhostip != _var($post,'internalip'));
}
if (!empty($post['externalhostname'])) {
// $post['externalhostname'] is $nginx['NGINX_CERTNAME'] (certificate_bundle.pem)
$externalhostip = host_lookup_ip(generate_external_host($post['externalhostname'], $wanip));
$externalhosterr = ($externalhostip != $wanip);
}
// anonymize data. no caclulations can be done with this data beyond this point.
if ($anon) {
if (!empty($certhostip)) $certhostip = anonymize_ip($certhostip);
if (!empty($certhostname)) $certhostname = anonymize_host($certhostname);
if (!empty($internalhostip)) $internalhostip = anonymize_ip($internalhostip);
if (!empty($externalhostip)) $externalhostip = anonymize_ip($externalhostip);
if (!empty($wanip)) $wanip = anonymize_ip($wanip);
if (!empty($post['internalip'])) $post['internalip'] = anonymize_ip($post['internalip']);
if (!empty($post['internalhostname'])) $post['internalhostname'] = anonymize_host($post['internalhostname']);
if (!empty($post['externalhostname'])) $post['externalhostname'] = anonymize_host($post['externalhostname']);
if (!empty($post['externalport'])) $post['externalport'] = "[redacted]";
}
// always anonymize the keyfile
if (!empty($post['keyfile'])) $post['keyfile'] = "[redacted]";
// output notes
if (!empty($post['internalprotocol']) && !empty($post['internalhostname']) && !empty($post['internalport'])) {
$localurl = $post['internalprotocol']."://".generate_internal_host($post['internalhostname'], _var($post,'internalip')).format_port($post['internalport']);
echo 'Local Access url: '.$localurl.PHP_EOL;
if ($internalhostip) {
// $internalhostip will not be defined for .local domains, ok to skip
echo ($internalhosterr) ? $icon_warn : $icon_ok;
echo generate_internal_host($post['internalhostname'], _var($post,'internalip'))." resolves to {$internalhostip}";
echo ($internalhosterr) ? ", it should resolve to "._var($post,'internalip') : "";
echo PHP_EOL;
}
if ($certhostname) {
echo ($certhosterr) ? $icon_warn : $icon_ok;
echo generate_internal_host($certhostname, _var($post,'internalip')).' ';
echo ($certhostip) ? "resolves to {$certhostip}" : "does not resolve to an IP address";
echo ($certhosterr) ? ", it should resolve to "._var($post,'internalip') : "";
echo PHP_EOL;
}
if ($remoteaccess == 'yes' && !empty($post['externalprotocol']) && !empty($post['externalhostname']) && !empty($post['externalport'])) {
$remoteurl = $post['externalprotocol']."://".generate_external_host($post['externalhostname'], $wanip).format_port($post['externalport']);
echo 'Remote Access url: '.$remoteurl.PHP_EOL;
echo ($externalhosterr) ? $icon_warn : $icon_ok;
echo generate_external_host($post['externalhostname'], $wanip).' ';
echo ($externalhosterr) ? "does not resolve to an IP address" : "resolves to ".($externalhostip??'');
echo PHP_EOL;
}
if ($reloadNginx) {
echo "IP address changes were detected, nginx was reloaded".PHP_EOL;
}
}
// output post data
echo PHP_EOL.'Request:'.PHP_EOL;
echo @json_encode($post, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
}
if ($result) {
echo "Response (HTTP $httpcode):".PHP_EOL;
$mutatedResult = is_array($result) ? json_encode($result) : $result;
echo @json_encode(@json_decode($mutatedResult, true), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL;
}
}
/**
* @name response_complete
* @param {HTTP Response Status Code} $httpcode https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
* @param {String|Array} $result - strings are assumed to be encoded JSON. Arrays will be encoded to JSON.
* @param {String} $cli_success_msg
*/
function response_complete($httpcode, $result, $cli_success_msg='') {
global $cli, $verbose;
$mutatedResult = is_array($result) ? json_encode($result) : $result;
if ($cli) {
if ($verbose) verbose_output($httpcode, $result);
$json = @json_decode($mutatedResult,true);
if (!empty($json['error'])) {
echo 'Error: '.$json['error'].PHP_EOL;
exit(1);
}
exit($cli_success_msg.PHP_EOL);
}
header('Content-Type: application/json');
http_response_code($httpcode);
exit((string)$mutatedResult);
}
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
require_once "$docroot/webGui/include/Wrappers.php";
// This is a stub, does nothing but return success
my_logger("This is a stub and should not be called", "UpdateDNS");
$cli = php_sapi_name()=='cli';
$verbose = $anon = false;
if ($cli && ($argc > 1) && $argv[1] == "-v") {
$verbose = true;
$anon = true;
}
if ($cli && ($argc > 1) && $argv[1] == "-vv") {
$verbose = true;
}
$var = @parse_ini_file('/var/local/emhttp/var.ini') ?: [];
$nginx = @parse_ini_file('/var/local/emhttp/nginx.ini') ?: [];
$is69 = version_compare(_var($var,'version'),"6.9.9","<");
$reloadNginx = false;
$dnserr = false;
$icon_warn = "⚠️ ";
$icon_ok = "✅ ";
$myservers_flash_cfg_path='/boot/config/plugins/dynamix.my.servers/myservers.cfg';
$myservers = file_exists($myservers_flash_cfg_path) ? @parse_ini_file($myservers_flash_cfg_path,true) : [];
// ensure some vars are defined here so we don't have to test them later
if (empty($myservers['remote']['apikey'])) {
$myservers['remote']['apikey'] = "";
}
if (empty($myservers['remote']['wanaccess'])) {
$myservers['remote']['wanaccess'] = "no";
}
if (empty($myservers['remote']['wanport'])) {
$myservers['remote']['wanport'] = 443;
}
// remoteaccess, externalport
if ($cli) {
$remoteaccess = empty($nginx['NGINX_WANFQDN']) ? 'no' : 'yes';
$externalport = $myservers['remote']['wanport'];
} else {
$remoteaccess = _var($_POST,'remoteaccess','no');
$externalport = intval(_var($_POST,'externalport',443));
if ($remoteaccess != 'yes') {
$remoteaccess = 'no';
}
if ($externalport < 1 || $externalport > 65535) {
$externalport = 443;
}
if ($myservers['remote']['wanaccess'] != $remoteaccess) {
// update the wanaccess ini value
$orig = file_exists($myservers_flash_cfg_path) ? parse_ini_file($myservers_flash_cfg_path,true) : [];
if (!$orig) {
$orig = ['remote' => $myservers['remote']];
}
$orig['remote']['wanaccess'] = $remoteaccess;
$text = '';
foreach ($orig as $section => $block) {
$pairs = "";
foreach ($block as $key => $value) if (strlen($value)) $pairs .= "$key=\"$value\"\n";
if ($pairs) $text .= "[$section]\n".$pairs;
}
if ($text) file_put_contents($myservers_flash_cfg_path, $text);
// need nginx reload
$reloadNginx = true;
}
exit("success".PHP_EOL);
}
$isRegistered = !empty($myservers['remote']['username']);
// protocols, hostnames, ports
$internalprotocol = 'http';
$internalport = _var($nginx,'NGINX_PORT');
$internalhostname = _var($nginx,'NGINX_LANMDNS');
$externalprotocol = 'https';
// keyserver will expand *.hash.myunraid.net or add www to hash.unraid.net as needed
$externalhostname = _var($nginx,'NGINX_CERTNAME');
$isLegacyCert = preg_match('/.*\.unraid\.net$/', _var($nginx,'NGINX_CERTNAME'));
$isWildcardCert = preg_match('/.*\.myunraid\.net$/', _var($nginx,'NGINX_CERTNAME'));
$internalip = _var($nginx,'NGINX_LANIP');
if (_var($nginx,'NGINX_USESSL')=='yes') {
// When NGINX_USESSL is 'yes' in 6.9, it could be using either Server_unraid_bundle.pem or certificate_bundle.pem
// When NGINX_USESSL is 'yes' in 6.10, it is is using Server_unraid_bundle.pem
$internalprotocol = 'https';
$internalport = _var($nginx,'NGINX_PORTSSL');
if ($is69 && _var($nginx,'NGINX_CERTNAME')) {
// this is from certificate_bundle.pem
$internalhostname = _var($nginx,'NGINX_CERTNAME');
}
}
if (_var($nginx,'NGINX_USESSL')=='auto') {
// NGINX_USESSL cannot be 'auto' in 6.9, it is either 'yes' or 'no'
// When NGINX_USESSL is 'auto' in 6.10, it is using certificate_bundle.pem
$internalprotocol = 'https';
$internalport = _var($nginx,'NGINX_PORTSSL');
// keyserver will expand *.hash.myunraid.net as needed
$internalhostname = _var($nginx,'NGINX_CERTNAME');
}
// My Servers version
$plgversion = file_exists("/var/log/plugins/dynamix.unraid.net.plg") ? trim(exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.plg 2>/dev/null'))
: (file_exists("/var/log/plugins/dynamix.unraid.net.staging.plg") ? trim(exec('/usr/local/sbin/plugin version /var/log/plugins/dynamix.unraid.net.staging.plg 2>/dev/null'))
: 'base-'._var($var,'version'));
// only proceed when when signed in or when legacy unraid.net SSL certificate exists
if (!$isRegistered && !$isLegacyCert) {
response_complete(406, ['error' => _('Nothing to do')]);
}
// keyfile
$keyfile = empty($var['regFILE']) ? false : @file_get_contents($var['regFILE']);
if ($keyfile === false) {
response_complete(406, ['error' => _('Registration key required')]);
}
$keyfile = @base64_encode($keyfile);
// build post array
$post = [
'keyfile' => $keyfile,
'plgversion' => $plgversion
];
if ($isLegacyCert) {
// sign in not required to maintain local ddns for unraid.net cert
// enable local ddns regardless of use_ssl value
$post['internalip'] = $internalip;
// if host.unraid.net does not resolve to the internalip and DNS Rebind Protection is disabled, disable caching
if (host_lookup_ip(generate_internal_host(_var($nginx,'NGINX_CERTNAME'), $post['internalip'])) != $post['internalip'] && rebindDisabled()) $dnserr = true;
}
if ($isRegistered) {
// if signed in, send data needed to maintain My Servers Dashboard
$post['internalhostname'] = $internalhostname;
$post['internalport'] = $internalport;
$post['internalprotocol'] = $internalprotocol;
$post['remoteaccess'] = $remoteaccess;
$post['servercomment'] = _var($var,'COMMENT');
$post['servername'] = _var($var,'NAME');
if ($isWildcardCert) {
// keyserver needs the internalip to generate the local access url
$post['internalip'] = $internalip;
}
if ($remoteaccess == 'yes') {
// include wanip in the cache file so we can track if it changes
$post['_wanip'] = trim(@file_get_contents("https://wanip4.unraid.net/"));
$post['externalhostname'] = $externalhostname;
$post['externalport'] = $externalport;
$post['externalprotocol'] = $externalprotocol;
// if wanip.hash.myunraid.net or www.hash.unraid.net does not resolve to the wanip, disable caching
if (host_lookup_ip(generate_external_host($post['externalhostname'], $post['_wanip'])) != $post['_wanip']) $dnserr = true;
}
}
// if remoteaccess is enabled in 6.10.0-rc3+ and WANIP has changed since nginx started, reload nginx
if (_var($post,'_wanip') != _var($nginx,'NGINX_WANIP') && version_compare(_var($var,'version'),"6.10.0-rc2",">")) $reloadNginx = true;
// if remoteaccess is currently disabled (perhaps because a wanip was not available when nginx was started)
// BUT the system is configured to have it enabled AND a wanip is now available
// then reload nginx
if ($remoteaccess == 'no' && _var($nginx,'NGINX_WANACCESS') == 'yes' && !empty(trim(@file_get_contents("https://wanip4.unraid.net/")))) $reloadNginx = true;
if ($reloadNginx) {
exec("/etc/rc.d/rc.nginx reload &>/dev/null");
}
// maxage is 36 hours
$maxage = 36*60*60;
if ($dnserr || $verbose) $maxage = 0;
$datafile = "/tmp/UpdateDNS.txt";
$datafiletmp = "/tmp/UpdateDNS.txt.new";
$dataprev = @file_get_contents($datafile) ?: '';
$datanew = implode("\n",$post)."\n";
if ($datanew == $dataprev && (time()-filemtime($datafile) < $maxage)) {
response_complete(204, null, _('No change to report'));
}
file_put_contents($datafiletmp,$datanew);
rename($datafiletmp, $datafile);
// do not submit the wanip, it will be captured from the submission if needed for remote access
unset($post['_wanip']);
// report necessary server details to limetech for DNS updates
$ch = curl_init('https://keys.lime-technology.com/account/server/register');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ( ($result === false) || ($httpcode != "200") ) {
// delete cache file to retry submission on next run
@unlink($datafile);
response_complete($httpcode ?? "500", ['error' => $error]);
}
response_complete($httpcode, $result, _('success'));
header('Content-Type: application/json');
http_response_code(204);
exit(0);
?>

View File

@@ -74,14 +74,14 @@ function ipaddr($ethX='eth0', $prot=4) {
global $$ethX;
switch (_var($$ethX,'PROTOCOL:0')) {
case 'ipv4':
return $$ethX['IPADDR:0'];
return _var($$ethX,'IPADDR:0');
case 'ipv6':
return $$ethX['IPADDR6:0'];
return _var($$ethX,'IPADDR6:0');
case 'ipv4+ipv6':
switch ($prot) {
case 4: return $$ethX['IPADDR:0'];
case 6: return $$ethX['IPADDR6:0'];
default:return [$$ethX['IPADDR:0'],$$ethX['IPADDR6:0']];}
case 4: return _var($$ethX,'IPADDR:0');
case 6: return _var($$ethX,'IPADDR6:0');
default:return [_var($$ethX,'IPADDR:0'),_var($$ethX,'IPADDR6:0')];}
default:
return _var($$ethX,'IPADDR:0');
}
@@ -91,4 +91,8 @@ function my_date($fmt, $time) {
$legacy = ['%c' => 'D j M Y h:i:s A T','%A' => 'l','%Y' => 'Y','%B' => 'F','%e' => 'j','%d' => 'd','%m' => 'm','%I' => 'h','%H' => 'H','%M' => 'i','%S' => 's','%p' => 'a','%R' => 'H:i', '%F' => 'Y-m-d', '%T' => 'H:i:s'];
return date(strtr($fmt,$legacy), $time);
}
// ensure params passed to logger are properly escaped
function my_logger($message, $logger='webgui') {
exec('logger -t '.escapeshellarg($logger).' -- '.escapeshellarg($message));
}
?>

View File

@@ -54,7 +54,7 @@ Q.find=(function(){var aP=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][
!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof exports?module.exports=e(require("jquery")):e(jQuery)}(function(p){var o=/\+/g;function f(e){return m.raw?e:encodeURIComponent(e)}function l(e,n){e=m.raw?e:function(e){0===e.indexOf('"')&&(e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return e=decodeURIComponent(e.replace(o," ")),m.json?JSON.parse(e):e}catch(e){}}(e);return p.isFunction(n)?n(e):e}var m=p.cookie=function(e,n,o){var i,t;if(1<arguments.length&&!p.isFunction(n))return"number"==typeof(o=p.extend({},m.defaults,o)).expires&&(t=o.expires,(i=o.expires=new Date).setMilliseconds(i.getMilliseconds()+864e5*t)),document.cookie=[f(e),"=",(t=n,f(m.json?JSON.stringify(t):String(t))),o.expires?"; expires="+o.expires.toUTCString():"",o.path?"; path="+o.path:"",o.domain?"; domain="+o.domain:"",o.samesite?"; samesite="+o.samesite:"",o.secure?"; secure":""].join("");for(var r=e?void 0:{},s=document.cookie?document.cookie.split("; "):[],c=0,a=s.length;c<a;c++){var u=s[c].split("="),d=(d=u.shift(),m.raw?d:decodeURIComponent(d)),u=u.join("=");if(e===d){r=l(u,n);break}e||void 0===(u=l(u))||(r[d]=u)}return r};m.defaults={path:"/",samesite:"lax"},p.removeCookie=function(e,n){return n=p.extend({},m.defaults,n),p.cookie(e,"",p.extend({},n,{expires:-1})),!p.cookie(e)}});
/* shortcuts - v2.01.B, copyright Binny V A NOT UPDATED */
shortcut={all_shortcuts:{},add:function(l,p,i){var e={type:"keydown",propagate:!1,disable_in_input:!1,target:document,keycode:!1};if(i)for(var t in e)void 0===i[t]&&(i[t]=e[t]);else i=e;var a=i.target;"string"==typeof i.target&&(a=document.getElementById(i.target));l=l.toLowerCase();function r(e){var t;if(e=e||window.event,!i.disable_in_input||(e.target?t=e.target:e.srcElement&&(t=e.srcElement),3==t.nodeType&&(t=t.parentNode),"INPUT"!=t.tagName&&"TEXTAREA"!=t.tagName)){e.keyCode?code=e.keyCode:e.which&&(code=e.which);var a=String.fromCharCode(code).toLowerCase();188==code&&(a=","),190==code&&(a=".");var r=l.split("+"),n=0,s={"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")","-":"_","=":"+",";":":","'":'"',",":"<",".":">","/":"?","\\":"|"},o={esc:27,escape:27,tab:9,space:32,return:13,enter:13,backspace:8,scrolllock:145,scroll_lock:145,scroll:145,capslock:20,caps_lock:20,caps:20,numlock:144,num_lock:144,num:144,pause:19,break:19,insert:45,home:36,delete:46,end:35,pageup:33,page_up:33,pu:33,pagedown:34,page_down:34,pd:34,left:37,up:38,right:39,down:40,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123},d={shift:{wanted:!1,pressed:!1},ctrl:{wanted:!1,pressed:!1},alt:{wanted:!1,pressed:!1},meta:{wanted:!1,pressed:!1}};e.ctrlKey&&(d.ctrl.pressed=!0),e.shiftKey&&(d.shift.pressed=!0),e.altKey&&(d.alt.pressed=!0),e.metaKey&&(d.meta.pressed=!0);for(var c=0;k=r[c],c<r.length;c++)"ctrl"==k||"control"==k?(n++,d.ctrl.wanted=!0):"shift"==k?(n++,d.shift.wanted=!0):"alt"==k?(n++,d.alt.wanted=!0):"meta"==k?(n++,d.meta.wanted=!0):1<k.length?o[k]==code&&n++:i.keycode?i.keycode==code&&n++:a==k?n++:s[a]&&e.shiftKey&&(a=s[a])==k&&n++;return n!=r.length||d.ctrl.pressed!=d.ctrl.wanted||d.shift.pressed!=d.shift.wanted||d.alt.pressed!=d.alt.wanted||d.meta.pressed!=d.meta.wanted||(p(e),i.propagate)?void 0:(e.cancelBubble=!0,e.returnValue=!1,e.stopPropagation&&(e.stopPropagation(),e.preventDefault()),!1)}}this.all_shortcuts[l]={callback:r,target:a,event:i.type},a.addEventListener?a.addEventListener(i.type,r,!1):a.attachEvent?a.attachEvent("on"+i.type,r):a["on"+i.type]=r},remove:function(e){e=e.toLowerCase();var t=this.all_shortcuts[e];if(delete this.all_shortcuts[e],t){var a=t.event,r=t.target,n=t.callback;r.detachEvent?r.detachEvent("on"+a,n):r.removeEventListener?r.removeEventListener(a,n,!1):r["on"+a]=!1}}};
/* Modified by Andrew Zawadzki - Changed variable code to be codeAZ due to conflict with const code in vue */
shortcut={all_shortcuts:{},add:function(l,p,i){var e={type:"keydown",propagate:!1,disable_in_input:!1,target:document,keycode:!1};if(i)for(var t in e)void 0===i[t]&&(i[t]=e[t]);else i=e;var a=i.target;"string"==typeof i.target&&(a=document.getElementById(i.target));l=l.toLowerCase();function r(e){var t;if(e=e||window.event,!i.disable_in_input||(e.target?t=e.target:e.srcElement&&(t=e.srcElement),3==t.nodeType&&(t=t.parentNode),"INPUT"!=t.tagName&&"TEXTAREA"!=t.tagName)){e.keyCode?codeAZ=e.keyCode:e.which&&(codeAZ=e.which);var a=String.fromCharCode(codeAZ).toLowerCase();188==codeAZ&&(a=","),190==codeAZ&&(a=".");var r=l.split("+"),n=0,s={"`":"~",1:"!",2:"@",3:"#",4:"$",5:"%",6:"^",7:"&",8:"*",9:"(",0:")","-":"_","=":"+",";":":","'":'"',",":"<",".":">","/":"?","\\":"|"},o={esc:27,escape:27,tab:9,space:32,return:13,enter:13,backspace:8,scrolllock:145,scroll_lock:145,scroll:145,capslock:20,caps_lock:20,caps:20,numlock:144,num_lock:144,num:144,pause:19,break:19,insert:45,home:36,delete:46,end:35,pageup:33,page_up:33,pu:33,pagedown:34,page_down:34,pd:34,left:37,up:38,right:39,down:40,f1:112,f2:113,f3:114,f4:115,f5:116,f6:117,f7:118,f8:119,f9:120,f10:121,f11:122,f12:123},d={shift:{wanted:!1,pressed:!1},ctrl:{wanted:!1,pressed:!1},alt:{wanted:!1,pressed:!1},meta:{wanted:!1,pressed:!1}};e.ctrlKey&&(d.ctrl.pressed=!0),e.shiftKey&&(d.shift.pressed=!0),e.altKey&&(d.alt.pressed=!0),e.metaKey&&(d.meta.pressed=!0);for(var c=0;k=r[c],c<r.length;c++)"ctrl"==k||"control"==k?(n++,d.ctrl.wanted=!0):"shift"==k?(n++,d.shift.wanted=!0):"alt"==k?(n++,d.alt.wanted=!0):"meta"==k?(n++,d.meta.wanted=!0):1<k.length?o[k]==codeAZ&&n++:i.keycode?i.keycode==codeAZ&&n++:a==k?n++:s[a]&&e.shiftKey&&(a=s[a])==k&&n++;return n!=r.length||d.ctrl.pressed!=d.ctrl.wanted||d.shift.pressed!=d.shift.wanted||d.alt.pressed!=d.alt.wanted||d.meta.pressed!=d.meta.wanted||(p(e),i.propagate)?void 0:(e.cancelBubble=!0,e.returnValue=!1,e.stopPropagation&&(e.stopPropagation(),e.preventDefault()),!1)}}this.all_shortcuts[l]={callback:r,target:a,event:i.type},a.addEventListener?a.addEventListener(i.type,r,!1):a.attachEvent?a.attachEvent("on"+i.type,r):a["on"+i.type]=r},remove:function(e){e=e.toLowerCase();var t=this.all_shortcuts[e];if(delete this.all_shortcuts[e],t){var a=t.event,r=t.target,n=t.callback;r.detachEvent?r.detachEvent("on"+a,n):r.removeEventListener?r.removeEventListener(a,n,!1):r["on"+a]=!1}}};
/* readmore.js - v2.0.0, copyright Jed Foster NOT UPDATED */
(function(c){function g(b,a){this.element=b;this.options=c.extend({},h,a);c(this.element).data("max-height",this.options.maxHeight);c(this.element).data("height-margin",this.options.heightMargin);delete this.options.maxHeight;if(this.options.embedCSS&&!k){var d=".readmore-js-toggle, .readmore-js-section { "+this.options.sectionCSS+" } .readmore-js-section { overflow: hidden; }",e=document.createElement("style");e.type="text/css";e.styleSheet?e.styleSheet.cssText=d:e.appendChild(document.createTextNode(d));document.getElementsByTagName("head")[0].appendChild(e);k=!0}this._defaults=h;this._name=f;this.init()}var f="readmore",h={speed:100,maxHeight:200,heightMargin:16,moreLink:'<a href="#">Read More</a>',lessLink:'<a href="#">Close</a>',embedCSS:!0,sectionCSS:"display: block; width: 100%;",startOpen:!1,expandedClass:"readmore-js-expanded",collapsedClass:"readmore-js-collapsed",beforeToggle:function(){},afterToggle:function(){}},k=!1;g.prototype={init:function(){var b=this;c(this.element).each(function(){var a=c(this),d=a.css("max-height").replace(/[^-\d\.]/g,"")>a.data("max-height")?a.css("max-height").replace(/[^-\d\.]/g,""):a.data("max-height"),e=a.data("height-margin");"none"!=a.css("max-height")&&a.css("max-height","none");b.setBoxHeight(a);if(a.outerHeight(!0)<=d+e)return!0;a.addClass("readmore-js-section "+b.options.collapsedClass).data("collapsedHeight",d);a.after(c(b.options.startOpen?b.options.lessLink:b.options.moreLink).on("click",function(c){b.toggleSlider(this,a,c)}).addClass("readmore-js-toggle"));b.options.startOpen||a.css({height:d})});c(window).on("resize",function(a){b.resizeBoxes()})},toggleSlider:function(b,a,d){d.preventDefault();var e=this;d=newLink=sectionClass="";var f=!1;d=c(a).data("collapsedHeight");c(a).height()<=d?(d=c(a).data("expandedHeight")+"px",newLink="lessLink",f=!0,sectionClass=e.options.expandedClass):(newLink="moreLink",sectionClass=e.options.collapsedClass);e.options.beforeToggle(b,a,f);c(a).animate({height:d},{duration:e.options.speed,complete:function(){e.options.afterToggle(b,a,f);c(b).replaceWith(c(e.options[newLink]).on("click",function(b){e.toggleSlider(this,a,b)}).addClass("readmore-js-toggle"));c(this).removeClass(e.options.collapsedClass+" "+e.options.expandedClass).addClass(sectionClass)}})},setBoxHeight:function(b){var a=b.clone().css({height:"auto",width:b.width(),overflow:"hidden"}).insertAfter(b),c=a.outerHeight(!0);a.remove();b.data("expandedHeight",c)},resizeBoxes:function(){var b=this;c(".readmore-js-section").each(function(){var a=c(this);b.setBoxHeight(a);(a.height()>a.data("expandedHeight")||a.hasClass(b.options.expandedClass)&&a.height()<a.data("expandedHeight"))&&a.css("height",a.data("expandedHeight"))})},destroy:function(){var b=this;c(this.element).each(function(){var a=c(this);a.removeClass("readmore-js-section "+b.options.collapsedClass+" "+b.options.expandedClass).css({"max-height":"",height:"auto"}).next(".readmore-js-toggle").remove();a.removeData()})}};c.fn[f]=function(b){var a=arguments;if(void 0===b||"object"===typeof b)return this.each(function(){if(c.data(this,"plugin_"+f)){var a=c.data(this,"plugin_"+f);a.destroy.apply(a)}c.data(this,"plugin_"+f,new g(this,b))});if("string"===typeof b&&"_"!==b[0]&&"init"!==b)return this.each(function(){var d=c.data(this,"plugin_"+f);d instanceof g&&"function"===typeof d[b]&&d[b].apply(d,Array.prototype.slice.call(a,1))})}})(jQuery);

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2021, Lime Technology
* Copyright 2012-2021, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -14,11 +14,19 @@
<?
$docroot = '/usr/local/emhttp';
$notify = "$docroot/webGui/scripts/notify";
$md5_old = -1;
require_once "$docroot/webGui/include/publish.php";
while (true) {
publish('notify', shell_exec("$notify get"));
$echo = shell_exec("$notify get");
if ( $echo ) {
$md5_new = md5($echo,true);
if ($md5_new !== $md5_old) {
publish('notify', $echo);
$md5_old = $md5_new;
}
}
sleep(3);
}
?>

View File

@@ -306,6 +306,36 @@ function geturls() {
return str_replace("\n", "\r\n", $urls);
}
// anonymize individual syslog files
function anonymize_syslog($file) {
global $diag, $all;
$max = 2*1024*1024; //=2MB
$log = "/$diag/logs/".basename($file);
run("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
if (!$all) {
unset($titles,$rows);
run("grep -Po 'file: \K[^\"\\x27]+' ".escapeshellarg("$log.txt")." 2>/dev/null|sort|uniq", $titles);
run("sed -ri 's|\b\S+@\S+\.\S+\b|email@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' ".escapeshellarg("$log.txt"));
run("sed -ri 's|(server: ).+(\.(my)?unraid\.net(:[0-9]+)?,)|\\1hash\\2|;s|(host: \").+(\.(my)?unraid\.net(:[0-9]+)?\")|\\1hash\\2|;s|(referrer: \"https?://).+(\.(my)?unraid\.net)|\\1hash\\2|' ".escapeshellarg("$log.txt"));
maskIP("$log.txt");
foreach ($titles as $mover) {
if (!$mover) continue;
$title = "/{$mover[0]}..".substr($mover,-1)."/...";
run("sed -i 's/".str_replace("/","\/",$mover)."/".str_replace("/","\/",$title)."/g' ".escapeshellarg("$log.txt")." 2>/dev/null");
//run("sed -ri 's|(file: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' ".escapeshellarg("$log.txt")." 2>/dev/null");
}
run("grep -n ' cache_dirs: -' ".escapeshellarg("$log.txt")." 2>/dev/null|cut -d: -f1", $rows);
for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) run("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' ".escapeshellarg("$log.txt")." 2>/dev/null");
}
// replace consecutive repeated lines in syslog
run("awk -i inplace '{if(s!=substr(\$0,17)){if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\";print;x=0}else{x++}s=substr(\$0,17)}END{if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\"}' ".escapeshellarg("$log.txt"));
// remove SHA256 hashes
run("sed -ri 's/(SHA256:).+[^\s\b]/SHA256:***REMOVED***/gm' $log.txt");
// truncate syslog if too big
if (basename($file)=='syslog' && filesize($file)>=$max) run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
}
// diagnostics start
run("mkdir -p /boot/logs");
@@ -612,32 +642,11 @@ foreach ($all_xml as $xml) {
}
// copy syslog information (anonymize if applicable)
$max = 2*1024*1024; //=2MB
foreach (glob("/var/log/syslog*") as $file) {
$log = "/$diag/logs/".basename($file);
run("todos <".escapeshellarg($file)." >".escapeshellarg("$log.txt"));
if (!$all) {
unset($titles,$rows);
run("grep -Po 'file: \K[^\"\\x27]+' ".escapeshellarg("$log.txt")." 2>/dev/null|sort|uniq", $titles);
run("sed -ri 's|\b\S+@\S+\.\S+\b|email@removed.com|;s|\b(username\|password)([=:])\S+\b|\\1\\2xxx|;s|(GUID: \S)\S+(\S) |\\1..\\2 |;s|(moving \"\S\|\"/mnt/user/\S).*(\S)\"|\\1..\\2\"|' ".escapeshellarg("$log.txt"));
run("sed -ri 's|(server: ).+(\.(my)?unraid\.net(:[0-9]+)?,)|\\1hash\\2|;s|(host: \").+(\.(my)?unraid\.net(:[0-9]+)?\")|\\1hash\\2|;s|(referrer: \"https?://).+(\.(my)?unraid\.net)|\\1hash\\2|' ".escapeshellarg("$log.txt"));
maskIP("$log.txt");
foreach ($titles as $mover) {
if (!$mover) continue;
$title = "/{$mover[0]}..".substr($mover,-1)."/...";
run("sed -i 's/".str_replace("/","\/",$mover)."/".str_replace("/","\/",$title)."/g' ".escapeshellarg("$log.txt")." 2>/dev/null");
//run("sed -ri 's|(file: [.>cr].*)[ /]$mover/.*$|\\1 file: $title|' ".escapeshellarg("$log.txt")." 2>/dev/null");
}
run("grep -n ' cache_dirs: -' ".escapeshellarg("$log.txt")." 2>/dev/null|cut -d: -f1", $rows);
for ($i = 0; $i < count($rows); $i += 2) for ($row = $rows[$i]+1; $row < $rows[$i+1]; $row++) run("sed -ri '$row s|(cache_dirs: \S).*(\S)|\\1..\\2|' ".escapeshellarg("$log.txt")." 2>/dev/null");
}
// replace consecutive repeated lines in syslog
run("awk -i inplace '{if(s!=substr(\$0,17)){if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\";print;x=0}else{x++}s=substr(\$0,17)}END{if(x>0)print\"### [PREVIOUS LINE REPEATED \"x\" TIMES] ###\\r\"}' ".escapeshellarg("$log.txt"));
// remove SHA256 hashes
run("sed -ri 's/(SHA256:).+[^\s\b]/SHA256:***REMOVED***/gm' $log.txt");
// truncate syslog if too big
if (basename($file)=='syslog' && filesize($file)>=$max) run("tail -n 200 ".escapeshellarg("$log.txt")." >".escapeshellarg("$log.last200.txt"));
run("truncate -s '<$max' ".escapeshellarg("$log.txt"));
anonymize_syslog($file);
}
foreach (glob("/boot/logs/syslog-previous*") as $file) {
anonymize_syslog($file);
}
// copy dhcplog
@@ -648,6 +657,13 @@ if (file_exists($dhcplog)) {
if (!$all) maskIP($log);
}
// copy phplog
$phplog = "/var/log/phplog";
if (file_exists($phplog)) {
$log = "/$diag/logs/phplog.txt";
run("todos <$phplog >".escapeshellarg($log));
}
// copy graphql-api.log
$graphql = "/var/log/graphql-api.log";
if (file_exists($graphql)) {

View File

@@ -209,6 +209,7 @@ $width = in_array($display['theme'], ['azure', 'gray']) ? '98.4%' : '100%';
troubleshoot_reset();
comment_reset();
$('#optFeatureRequest').click();
$('button.confirm').text("<?=_('Cancel')?>");
});
</script>
</body>

View File

@@ -25,7 +25,7 @@ function update_wireguard($ifname) {
$vtun = basename($wg,'.conf');
// interface has changed?
if (exec("grep -Pom1 ' dev $nic ' $wg")=='') {
exec("logger -t netconfig 'updated wireguard $vtun configuration'");
exec("logger -t netconfig -- \"updated wireguard $vtun configuration\"");
exec("sed -ri 's/ dev (br0|bond0|eth0) / dev $nic /' $wg");
}
// restart active wireguard tunnels
@@ -81,7 +81,7 @@ if ($run) {
}
// create configuration file for all available interfaces
$i = 0; $new = []; $new[] = "# Generated settings:";
$i = 0; $new = ["# Generated settings:"];
foreach ($ini as $name => $port) {
$bonding = $port['BONDING']=='yes';
$bridging = $port['BRIDGING']=='yes';
@@ -126,8 +126,8 @@ file_put_contents($cfg,implode("\r\n",$new)."\r\n");
// start interface with updated (new) configuration
// don't execute when only interface description has changed
if ($run) {
exec("/etc/rc.d/rc.inet1 {$ifname}_start >/dev/null 2>&1");
exec("/usr/local/sbin/create_network_ini $ifname >/dev/null 2>&1 &");
exec("/etc/rc.d/rc.inet1 {$ifname}_start &>/dev/null");
exec("/usr/local/sbin/create_network_ini $ifname &>/dev/null &");
update_wireguard($ifname);
}
exit(0);

View File

@@ -0,0 +1,23 @@
#!/usr/bin/php -q
<?
$docroot = $docroot ?? $_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp';
require_once "$docroot/plugins/dynamix/include/Wrappers.php";
require_once "$docroot/plugins/dynamix/include/ReplaceKey.php";
$randomMinute = rand(0, 59);
switch (@$argv[1] ?? '') {
case 'cron-init':
$text = <<<EOT
# Create replace key job:
$randomMinute * * * * /usr/local/emhttp/plugins/dynamix/scripts/replace_key_job &> /dev/null
EOT;
parse_cron_cfg("dynamix", "replace-key-job", $text);
break;
default:
$ReplaceKey = new ReplaceKey();
$ReplaceKey->check();
break;
}

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2024, Lime Technology
* Copyright 2012-2024, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -20,6 +20,7 @@ require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/webGui/include/CustomMerge.php";
$script = "$docroot/webGui/scripts/notify";
// this command will set the $notify array
extract(parse_plugin_cfg("dynamix",true));
$output = _var($notify,'report');
$server = strtoupper(_var($var,'NAME','tower'));
@@ -176,7 +177,8 @@ $warn = ($error0 || $error3) ? "alert" : (($error1 || $error2) ? "warning" : "no
$stat = $warn=="normal" ? "[PASS]" : "[FAIL]";
$info = "Array has $size disk".($size==1 ? "" : "s").($parity ? " ({$word}parity".($pools ? " & pools)" : ")") : ($pools ? " ({$word}pools)" : ""));
$message = implode('\n', $data);
exec("$script -s ".escapeshellarg("Notice [$server] - array health report $stat")." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'");
$subject = "Notice [$server] - array health report $stat";
exec("$script -s ".escapeshellarg($subject)." -d ".escapeshellarg("$info")." -m ".escapeshellarg("$message")." -i ".escapeshellarg("$warn $output")." -l '/Main'");
exit(0);
?>

View File

@@ -2,7 +2,7 @@ html{font-family:clear-sans;font-size:62.5%;height:100%}
body{font-size:1.3rem;color:#606e7f;background-color:#e4e2e4;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
@media (min-width:1281px){#template{min-width:1260px;margin:0}}
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
img{border:none;text-decoration:none;vertical-align:middle}
p{text-align:left}
p.centered{text-align:left}

View File

@@ -1,8 +1,8 @@
html{font-family:clear-sans;font-size:62.5%;height:100%}
body{font-size:1.3rem;color:#f2f2f2;background-color:#1c1b1b;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
@media (max-width:1280px){#templsate{min-width:1260px;max-width:1260px;margin:0}}
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
@media (min-width:1281px){#template{min-width:1260px;margin:0 10px}}
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
img{border:none;text-decoration:none;vertical-align:middle}
p{text-align:justify}
p.centered{text-align:left}

View File

@@ -2,7 +2,7 @@ html{font-family:clear-sans;font-size:62.5%;height:100%}
body{font-size:1.3rem;color:#606e7f;background-color:#1b1d1b;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
@media (min-width:1281px){#template{min-width:1260px;margin:0}}
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
img{border:none;text-decoration:none;vertical-align:middle}
p{text-align:left}
p.centered{text-align:left}

View File

@@ -2,7 +2,7 @@ html{font-family:clear-sans;font-size:62.5%;height:100%}
body{font-size:1.3rem;color:#1c1b1b;background-color:#f2f2f2;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
@media (max-width:1280px){#template{min-width:1260px;max-width:1260px;margin:0}}
@media (min-width:1281px){#template{min-width:1260px;margin:0 10px}}
@media (min-width:1921px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
@media (min-width:1920px){#template{min-width:1260px;max-width:1920px;margin:0 auto}}
img{border:none;text-decoration:none;vertical-align:middle}
p{text-align:justify}
p.centered{text-align:left}

View File

@@ -49,7 +49,7 @@ if (isset($_POST['#file'])) {
$cleanup = isset($_POST['#cleanup']);
$default = ($file && isset($_POST['#default'])) ? @parse_ini_file("$docroot/plugins/".basename(dirname($file))."/default.cfg", $section) : [];
$keys = @parse_ini_file($file, $section) ?: [];
$keys = is_file($file) ? (parse_ini_file($file, $section) ?: []) : [];
// the 'save' switch can be reset by the include file to disallow settings saving
$save = true;
if (isset($_POST['#include'])) {

View File

@@ -22,6 +22,7 @@ DOCKER_PIDFILE=/var/run/$DOCKERD.pid
DOCKER_LOG=/var/log/docker.log
DOCKER_ROOT=/var/lib/docker
DOCKER_CFG=/boot/config/docker.cfg
DOCKER_TIMEOUT=$(awk -F'"' '/^DOCKER_TIMEOUT=/{print $2}' $DOCKER_CFG 2>/dev/null)
STOCK="eth br bond"
# network file references
@@ -40,7 +41,8 @@ if [[ -f $DOCKER_CFG ]]; then
elif [[ -e $SYSTEM/${NIC/eth/bond} ]]; then
NIC=${NIC/eth/bond}
fi
if ! grep -qPm1 "_${NIC^^}(_[0-9]+)?=" $DOCKER_CFG; then
CFG=($(grep -Pom2 "_SUBNET_|_${NIC^^}(_[0-9]+)?=" $DOCKER_CFG))
if [[ ${CFG[0]} == _SUBNET_ && -z ${CFG[1]} ]]; then
# interface has changed, update configuration
X=${NIC//[^0-9]/}
sed -ri "s/_(BR|BOND|ETH)$X(_[0-9]+)?=/_${NIC^^}\2=/; s/(br|bond|eth)$X(\.[0-9]+)? /$NIC\2 /g" $DOCKER_CFG
@@ -117,46 +119,6 @@ running_containers(){
docker ps --format='{{.Names}}' 2>/dev/null
}
max6() {
# ipv6 addresses in long notation
f=:ffff:
for x in $*; do
read a m < <(IFS=/; echo $x)
[[ $a =~ $f && $a =~ '.' ]] && b=${a#*$f} a=${a%$f*}$f:0 || b=
c=${a//[^:]/}
[[ ${a:0:1} == : ]] && a=0${a}
[[ ${a:${#a}-1} == : ]] && a=${a}0
a=${a/::/:$(for((i=1;i<=$((8-${#c}));i++)); do printf "0:"; done)}
d= a=$(for q in ${a//:/ }; do printf "$d%04x" "0x$q"; d=:; done)
[[ -n $b ]] && d= a=${a%$f*}${f}$(for q in ${b//./ }; do printf "$d%03x" "0x$q"; d=.; done)
[[ -z $m ]] && echo $a || echo $a/$m
done
}
min6() {
# ipv6 address in short notation
f=:ffff:
[[ -n $1 ]] && read a m < <(IFS=/; echo $1) || return
[[ $a =~ $f && $a =~ '.' ]] && b=${a#*$f} a=${a%$f*}$f || b=
d= a=:$(for q in ${a//:/ }; do printf "$d%x" "0x$q"; d=:; done)
a=${a/$(grep -Po ':(0(:|$)){2,8}' <<< $a|sort|tail -1)/::}
[[ ${a:0:2} != :: ]] && a=${a:1}
[[ -n $b ]] && d= a=${a%$f*}:$(for q in ${b//./ }; do printf "$d%x" "0x$q"; d=.; done)
[[ -z $m ]] && echo $a || echo $a/$m
}
wipe() {
wet=($*)
# remove temporary (privacy extensions) and host ipv6 addresses
for tmp in $(ip -br -6 addr show scope global temporary dev $wet 2>/dev/null|awk '{$1=$2="";print}'); do
for i in ${!wet[@]}; do
[[ ${wet[$i]} == $tmp || (${wet[$i]} =~ '::' && ${wet[$i]#*/} == 128) ]] && unset 'wet[i]'
done
done
# return cleaned-up list without interface name
echo ${wet[@]/$wet}
}
# Network driver
driver() {
# user selection when bridge is enabled
@@ -221,11 +183,12 @@ add_route(){
local CT=($(docker inspect --format='{{.State.Pid}} {{.NetworkSettings.Networks}}' $1))
local PID=${CT[0]}
local NET=${CT[1]#*[}
if [[ $PID -gt 0 && ${NET%%:*} == br0 ]]; then
local LAN=${NET%:*}
if [[ $PID -gt 0 && "eth0 br0 bond0" =~ $LAN ]]; then
local THISIP=$(sed -n '/^\[eth0\]$/,/^TYPE/p' $INI|grep -Pom1 '^IPADDR:0="\K[^"]+')
for CFG in /etc/wireguard/wg*.cfg ; do
local NETWORK=$(grep -Pom1 '^Network:0="\K[^"]+' $CFG)
[[ -n $NETWORK ]] && nsenter -n -t $PID ip -4 route add $NETWORK via $THISIP dev br0 2>/dev/null
[[ -n $NETWORK ]] && nsenter -n -t $PID ip -4 route add $NETWORK via $THISIP dev $LAN 2>/dev/null
done
fi
}
@@ -347,7 +310,8 @@ start_network(){
GATEWAY=$(ip -4 route show default dev $NETWORK|awk '{print $3;exit}')
fi
SUBNET6=; GATEWAY6=; SERVER6=; RANGE6=;
IPV6=$(min6 $(max6 $(wipe $(ip -br -6 addr show $NETWORK scope global|awk '{$2="";print;exit}'))|sort|head -1))
IPV6=$(ip -br -6 addr show $NETWORK scope global mngtmpaddr|awk '{print $3;exit}')
[[ -z $IPV6 ]] && IPV6=$(ip -br -6 addr show $NETWORK scope global permanent|awk '{print $3;exit}')
if [[ -n $IPV6 ]]; then
# get IPV6 subnet, preset to /64 if single host address is given
[[ ${IPV6#*/} == 128 ]] && SUBNET6=$(echo $IPV6|sed -r 's/^([^:]+):([^:]+):([^:]+):([^:]+).*$/\1:\2:\3:\4::\/64/') || SUBNET6=$(ip -6 route show $IPV6 dev $NETWORK|awk '{print $1;exit}')
@@ -542,7 +506,9 @@ start_containers(){
# Stop containers
stop_containers(){
[[ ! -z $(running_containers) ]] && docker stop $(running_containers) >/dev/null
[[ -n $(running_containers) ]] && docker stop --time=${DOCKER_TIMEOUT:-10} $(running_containers) >/dev/null
# Kill containers if still running
docker kill $(docker ps -q) 2>/dev/null
}
# Start docker
@@ -573,23 +539,35 @@ stop_docker(){
echo "stopping $DOCKERD ..."
# If there is no PID file, ignore this request...
if [[ -r $DOCKER_PIDFILE ]]; then
# Try to stop dockerd gracefully
kill $(docker_pid) 2>/dev/null
local TIMER=15
# must ensure daemon has exited
for n in {1..15}; do
while [[ $TIMER -gt 0 ]]; do
sleep 1
if [[ $(ps -p $(docker_pid) -o comm= 2>/dev/null) != $DOCKERD ]]; then
rm -f $DOCKER_PIDFILE
# tear down the bridge
if ip link show docker0 >/dev/null 2>&1; then
if [[ -e $SYSTEM/docker0 ]]; then
ip link set docker0 down
ip link del docker0
fi
return
# signal succesful stop
TIMER=-1
else
# show waiting message
echo "$DAEMON... Waiting to die."
((TIMER--))
fi
echo "waiting for docker to die ..."
done
echo "docker will not die!"
exit 1
if [[ $TIMER -eq 0 ]]; then
echo "Error: process will not die!"
# Send SIGKILL to dockerd
kill -SIGKILL $(docker_pid) 2>/dev/null
# Remove .sock and .pid
rm -f /var/run/docker.sock $DOCKER_PIDFILE
echo "$DAEMON... Killed."
fi
fi
}

View File

@@ -56,6 +56,16 @@
# - added macvtap network creation
# - removed unnecessary error output redirection for 'run' command
# Adapted by Bergware for use in Unraid OS - December 2023
# - added interface carrier check before assigning IP address (DHCP or static)
# - added "status" command
# - remove leading zeros in IPv4 and IPv6 addresses
# Adapted by Bergware for use in Unraid OS - February 2024
# - revised bond interface creation for linux kernel 6.1.75 and later point releases
# Bergware - modified for Unraid OS, February 2024
############################
# READ NETWORK CONFIG FILE #
############################
@@ -63,10 +73,8 @@
# get the configuration information from rc.inet1.conf
. /etc/rc.d/rc.inet1.conf
# system network reference
# system network references
SYSTEM=/sys/class/net
# ipv6 config reference
CONF6=/proc/sys/net/ipv6/conf
###########
@@ -149,26 +157,32 @@ set_mtu(){
fi
}
# function to wait for carrier of interface
carrier_up(){
local n
for n in {1..10}; do
[[ $(cat $SYSTEM/$1/carrier 2>/dev/null) == 1 ]] && return 0 || sleep 1
done
return 1
}
# function to create bond interface
bond_up(){
[[ -d /proc/net/bonding ]] || modprobe bonding mode=${BONDING_MODE[$i]} miimon=${BONDING_MIIMON[$i]}
run ip link add name ${BONDNAME[$i]} type bond mode ${BONDING_MODE[$i]} miimon ${BONDING_MIIMON[$i]}
run ip link set ${BONDNAME[$i]} up
set_mtu ${BONDNAME[$i]}
PRIMARY=;
# loop thru assigned interfaces in bond
for BONDIF in ${BONDNICS[$i]}; do
if [[ -e $SYSTEM/$BONDIF ]]; then
[[ -z $PRIMARY ]] && PRIMARY=$BONDIF
run ip link set $BONDIF down
run ip link set $BONDIF master ${BONDNAME[$i]} up type bond_slave
run ip link set $BONDIF up
run ip link set $BONDIF master ${BONDNAME[$i]} down type bond_slave
else
[[ $DEBUG_ETH_UP == yes ]] && log "interface $BONDIF not present, can't add to ${BONDNAME[$i]}"
fi
done
[[ -n $PRIMARY ]] && run ip link set name ${BONDNAME[$i]} type bond primary $PRIMARY
# delay to allow bond initialization
sleep 3
}
# function to delete bond interface
@@ -194,7 +208,6 @@ br_up(){
BRSTP[$i]=${BRSTP[$i]/no/0}
BRSTP[$i]=${BRSTP[$i]/yes/1}
run ip link add name $BRIDGE type bridge stp_state ${BRSTP[$i]} forward_delay ${BRFD[$i]}
run ip link set $BRIDGE up
# loop thru assigned interfaces in bridge
for BRNIC in ${BRNICS[$i]}; do
[[ $j -eq 0 ]] && BRIF=$BRNIC || BRIF=$BRNIC.${VLANID[$i,$j]}
@@ -347,27 +360,35 @@ ipaddr_up(){
[[ $IP == ipv4 ]] && DHCP_OPTIONS="$DHCP_OPTIONS -4"
[[ $IP == ipv6 ]] && DHCP_OPTIONS="$DHCP_OPTIONS -6"
[[ $IP != ipv4 && -n $PRIV6 && -d $CONF6/$IFACE ]] && echo $PRIV6 >$CONF6/$IFACE/use_tempaddr
log "polling up to 60 sec for DHCP server on interface $IFACE"
if ! run timeout 60 dhcpcd -w $DHCP_OPTIONS $IFACE; then
log "can't obtain IP address, continue polling in background on interface $IFACE"
if carrier_up $IFACE; then
# interface is UP
log "interface $IFACE is UP, polling up to 60 sec for DHCP $IP server"
if ! run timeout 60 dhcpcd -w $DHCP_OPTIONS $IFACE; then
log "can't obtain IP address, continue polling in background on interface $IFACE"
run dhcpcd -b $DHCP_OPTIONS $IFACE
fi
else
# interface is DOWN
log "interface $IFACE is DOWN, polling DHCP $IP server in background"
run dhcpcd -b $DHCP_OPTIONS $IFACE
fi
[[ $j -eq $((${VLANS[$i]}-1)) ]] && sleep 3
elif [[ $DHCP == no ]]; then
# bring up interface using static IP address
if carrier_up $IFACE; then STATE="UP"; else STATE="DOWN"; fi
log "interface $IFACE is $STATE, setting static $IP address"
ipv6_addr 0 1
if [[ $IP != ipv6 ]]; then
[[ $j -eq 0 ]] && ADDR=${IPADDR[$i]} || ADDR=${IPADDR[$i,$j]}
if [[ -n $ADDR ]]; then
[[ $j -eq 0 ]] && MASK=${NETMASK[$i]} || MASK=${NETMASK[$i,$j]}
[[ -n $MASK ]] && run ip -4 addr add $ADDR/$MASK dev $IFACE metric 1
[[ -n $MASK ]] && run ip -4 addr add $(unzero $ADDR)/$MASK dev $IFACE metric 1
fi
fi
if [[ $IP != ipv4 ]]; then
[[ $j -eq 0 ]] && ADDR6=${IPADDR6[$i]} || ADDR6=${IPADDR6[$i,$j]}
if [[ -n $ADDR6 ]]; then
[[ $j -eq 0 ]] && MASK6=${NETMASK6[$i]} || MASK6=${NETMASK6[$i,$j]}
[[ -n $MASK6 ]] && run ip -6 addr add $ADDR6/$MASK6 dev $IFACE metric 1
[[ -n $MASK6 ]] && run ip -6 addr add $(unzero6 $ADDR6)/$MASK6 dev $IFACE metric 1
[[ -n $PRIV6 && -d $CONF6/$IFACE ]] && echo 0 >$CONF6/$IFACE/use_tempaddr
fi
fi
@@ -425,8 +446,7 @@ if_up(){
# set index of INTERFACE in array
i=0
while [[ $i -lt $MAXNICS ]]; do
[[ ${IFNAME[$i]} == $1 ]] && break
((i++))
[[ ${IFNAME[$i]} == $1 ]] && break || ((i++))
done
# exit when interface is not found
[[ $i -eq $MAXNICS ]] && break
@@ -461,6 +481,7 @@ if_up(){
[[ -n ${HWADDR[$i]} ]] && run ip link set $1 addr ${HWADDR[$i]}
set_mtu $1
fi
run ip link set $IFACE up
# set interface address
[[ $i -eq 0 && $j -eq 0 ]] && MAIN=1 || MAIN=
if [[ $IP == ipv4 ]]; then
@@ -490,7 +511,6 @@ if_up(){
DHCP_KEEP_RESOLV=$DHCP6_KEEP_RESOLV
ipaddr_up
fi
run ip link set $IFACE up
done
}
@@ -536,10 +556,10 @@ if_down(){
[[ $DEBUG_ETH_UP == yes ]] && log "interface $IFACE not present, can't take down"
fi
done
[[ -z ${BRNICS[$i]} ]] && macvtap_down # delete macvtap interfaces
[[ -n ${BRNICS[$i]} ]] && br_down # delete interface as bridge
[[ -n ${VLANS[$i]} ]] && vlan_down # delete interface VLANs
[[ -n ${BONDNICS[$i]} ]] && bond_down # delete interface as bond
[[ -z ${BRNICS[$i]} ]] && macvtap_down # delete macvtap interfaces
[[ -n ${BRNICS[$i]} ]] && br_down # delete interface as bridge
[[ -n ${VLANS[$i]} ]] && vlan_down # delete interface VLANs
[[ -n ${BONDNICS[$i]} ]] && bond_down # delete interface as bond
}
#####################
@@ -557,8 +577,8 @@ gateway_up(){
IP=${PROTOCOL[$x]:-ipv4}
AD=${METRIC[$x]}
[[ -n $AD ]] && AD="metric $AD"
EXIST=$(ip -4 route show default via $GW dev $DEV|grep "$AD ")
[[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $GW dev $DEV $AD
EXIST=$(ip -4 route show default via $(unzero $GW) dev $DEV|grep "$AD ")
[[ $IP != ipv6 && -z $EXIST ]] && run ip -4 route add default via $(unzero $GW) dev $DEV $AD
done
for GW6 in ${GATEWAY6[@]}; do
[[ -z $GW6 ]] && continue
@@ -569,8 +589,8 @@ gateway_up(){
IP=${PROTOCOL[$x]:-ipv4}
AD6=${METRIC6[$x]}
[[ -n $AD6 ]] && AD6="metric $AD6"
EXIST=$(ip -6 route show default via $GW6 dev $DEV|grep "$AD6 ")
[[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $GW6 dev $DEV $AD6
EXIST=$(ip -6 route show default via $(unzero6 $GW6) dev $DEV|grep "$AD6 ")
[[ $IP != ipv4 && -z $EXIST ]] && run ip -6 route add default via $(unzero6 $GW6) dev $DEV $AD6
done
}
@@ -616,6 +636,13 @@ stop(){
lo_down
}
# function to show network status
status(){
echo "INTERFACE STATE INFORMATION"
echo "========================================================================"
[[ $1 == ip ]] && ip -brief addr || ip -brief link
}
##########################
# STATIC ROUTE FUNCTIONS #
##########################
@@ -660,50 +687,54 @@ route_down(){
### MAIN ###
############
case $1 in
case "$1" in
start|up)
start
;;
;;
stop|down)
stop
;;
;;
restart)
stop
sleep 1
start
;;
;;
*_start|*_up)
INTERFACE=$(echo $1|cut -d_ -f1)
if_up $INTERFACE
gateway_up
;;
;;
*_stop|*_down)
INTERFACE=$(echo $1|cut -d_ -f1)
if_down $INTERFACE
;;
;;
*_restart)
INTERFACE=$(echo $1|cut -d_ -f1)
if_down $INTERFACE
sleep 1
if_up $INTERFACE
gateway_up
;;
;;
*_add)
INTERFACE=$(echo $1|cut -d_ -f1)
ROUTE=$(echo $1|cut -d_ -f2)
METRIC=$(echo $1|cut -d_ -f3)
[[ $METRIC == add ]] && METRIC=
route_up $INTERFACE $ROUTE $METRIC
;;
;;
*_del)
INTERFACE=$(echo $1|cut -d_ -f1)
ROUTE=$(echo $1|cut -d_ -f2)
METRIC=$(echo $1|cut -d_ -f3)
[[ $METRIC == del ]] && METRIC=
route_down $INTERFACE $ROUTE $METRIC
;;
# default is to bring up the entire network
*) start
;;
status)
status $2
;;
# default is to bring up the entire network
*)
start
esac
# Command examples
@@ -719,3 +750,5 @@ esac
# rc.inet1 10.0.0.1_default_add add default route to gateway 10.0.0.1 with metric 1
# rc.inet1 eth0_10.0.0.0/24_1_del delete specific route & metric from interface eth0
# rc.inet1 10.0.0.1_default_del delete default route from gateway 10.0.0.1
# rc.inet1 status show link status
# rc.inet1 status ip show ip status

View File

@@ -7,27 +7,49 @@
# You can configure network interfaces other than eth0,eth1... by setting
# IFNAME[interface] to the interface's name. If IFNAME[interface] is unset
# or empty, it is assumed you're configuring eth<interface>.
# =============================================================================
# change this to "yes" for debugging output to stdout. Unfortunately,
# /sbin/hotplug seems to disable stdout so you'll only see debugging output
# when rc.inet1 is called directly.
# Adapted by Bergware for use in Unraid OS - December 2023
# - added functions to remove leading zeros in IPv4 and IPv6 addresses
# LimeTech - modified for Unraid OS
# Bergware - modified for Unraid OS, December 2023
# change this to "yes" for debugging output to stdout.
# Unfortunately, /sbin/hotplug seems to disable stdout so you'll only see debugging output when rc.inet1 is called directly.
DEBUG_ETH_UP=no
DHCP_DEBUG=no
# function to remove leading zeros in IPv4 address
unzero(){
local M Q
echo -n $(for Q in ${1//./ }; do printf "$M%x" "0x$Q"; M=.; done)
}
# function to remove leading zeros in IPv6 address
unzero6(){
local A M Q
A=${1/::/:-:}
echo -n $(for Q in ${A//:/ }; do [[ $Q != - ]] && printf "$M%x" "0x$Q" || printf ":"; M=:; done)
}
# bergware - use associative format for multi-dimensional arrays
declare -A VLANID USE_DHCP IPADDR NETMASK GATEWAY METRIC USE_DHCP6 IPADDR6 NETMASK6 GATEWAY6 METRIC6 PRIVACY6 DESCRIPTION PROTOCOL
# limetech - read settings from config file
cfg=/boot/config/network.cfg
if [[ -s $cfg ]]; then
source <(/usr/bin/fromdos < $cfg)
CFG=/boot/config/network.cfg
if [[ -s $CFG ]]; then
. <(fromdos <$CFG)
else
# default legacy settings
IPADDR=
NETMASK=
GATEWAY=
PROTOCOL=ipv4
USE_DHCP=yes
USE_DHCP6=
DHCP_KEEPRESOLV=no
DHCP6_KEEPRESOLV=no
BONDING=yes
BRIDGING=yes
fi
@@ -54,27 +76,43 @@ echo -n >$RESOLV.tail
if [[ $DHCP_KEEPRESOLV == yes ]]; then
echo "# Generated by rc.inet1" >>$RESOLV
[[ -n $DNS_SERVER1 ]] && echo "nameserver $DNS_SERVER1" >>$RESOLV
[[ -n $DNS_SERVER2 ]] && echo "nameserver $DNS_SERVER2" >>$RESOLV
[[ -n $DNS_SERVER3 ]] && echo "nameserver $DNS_SERVER3" >>$RESOLV
[[ -n $DNS_SERVER4 ]] && echo "nameserver $DNS_SERVER4" >>$RESOLV
[[ -n $DNS_SERVER1 ]] && echo "nameserver $(unzero $DNS_SERVER1)" >>$RESOLV
[[ -n $DNS_SERVER2 ]] && echo "nameserver $(unzero $DNS_SERVER2)" >>$RESOLV
[[ -n $DNS_SERVER3 ]] && echo "nameserver $(unzero $DNS_SERVER3)" >>$RESOLV
[[ -n $DNS_SERVER4 ]] && echo "nameserver $(unzero $DNS_SERVER4)" >>$RESOLV
[[ $DHCP6_KEEPRESOLV == no ]] && cp -f $RESOLV $RESOLV.head
fi
if [[ $DHCP6_KEEPRESOLV == yes ]]; then
[[ $DHCP_KEEPRESOLV == no ]] && echo "# Generated by rc.inet1" >>$RESOLV
[[ -n $DNS6_SERVER1 ]] && echo "nameserver $DNS6_SERVER1" >>$RESOLV
[[ -n $DNS6_SERVER2 ]] && echo "nameserver $DNS6_SERVER2" >>$RESOLV
[[ -n $DNS6_SERVER3 ]] && echo "nameserver $DNS6_SERVER3" >>$RESOLV
[[ -n $DNS6_SERVER4 ]] && echo "nameserver $DNS6_SERVER4" >>$RESOLV
[[ -n $DNS6_SERVER1 ]] && echo "nameserver $(unzero6 $DNS6_SERVER1)" >>$RESOLV
[[ -n $DNS6_SERVER2 ]] && echo "nameserver $(unzero6 $DNS6_SERVER2)" >>$RESOLV
[[ -n $DNS6_SERVER3 ]] && echo "nameserver $(unzero6 $DNS6_SERVER3)" >>$RESOLV
[[ -n $DNS6_SERVER4 ]] && echo "nameserver $(unzero6 $DNS6_SERVER4)" >>$RESOLV
[[ $DHCP_KEEPRESOLV == no ]] && cp -f $RESOLV $RESOLV.tail
fi
make_cfg(){
[[ -s $CFG ]] && return
for VAR in "$@"; do
if [[ ${VAR:0:1} == '#' ]]; then
# add comment
echo -ne "$VAR\r\n" >>$CFG
elif [[ ${VAR: -1} == '#' ]]; then
# add global variable
VAR=${VAR::-1}
echo -ne "$VAR=\"${!VAR}\"\r\n" >>$CFG
else
# add interface variable
echo -ne "$VAR[0]=\"${!VAR}\"\r\n" >>$CFG
fi
done
}
if [[ -n $SYSNICS ]]; then
# bergware - set number of interfaces as present in the system
MAXNICS=$SYSNICS
else
# bergware - legacy configuration of first interface
MAXNICS=1
if [[ $BONDING == yes && $BRIDGING == yes ]]; then
# both bonding and bridging selected
BONDNAME=bond0
@@ -86,6 +124,7 @@ else
BRSTP=no
BRFD=0
IFNAME=$BRNAME
SETTINGS="BONDNAME BONDNICS BONDING_MODE BONDING_MIIMON BRNAME BRNICS BRSTP BRFD"
elif [[ $BONDING == yes ]]; then
# bonding selected
BONDNAME=bond0
@@ -93,6 +132,7 @@ else
BONDING_MODE=${BONDING_MODE:-1}
BONDING_MIIMON=${BONDING_MIIMON:-100}
IFNAME=$BONDNAME
SETTINGS="BONDNAME BONDNICS BONDING_MODE BONDING_MIIMON"
elif [[ $BRIDGING == yes ]]; then
# bridging selected
BRNAME=br0
@@ -100,8 +140,12 @@ else
BRSTP=no
BRFD=0
IFNAME=$BRNAME
SETTINGS="BRNAME BRNICS BRSTP BRFD"
else
# normal interface
IFNAME=eth0
fi
SYSNICS=1
MAXNICS=$SYSNICS
make_cfg "# Generated settings:" IFNAME DHCP_KEEPRESOLV# DHCP6_KEEPRESOLV# $SETTINGS PROTOCOL USE_DHCP USE_DHCP6 SYSNICS#
fi

View File

@@ -47,13 +47,13 @@ scan() {
}
good() {
data=;
data=
for i in ${bind[@]}; do
[[ $i == $1 || ${1:0:4} == fe80 ]] && data=$1
[[ $i == $1 || $1 == 0 || ${1:0:4} == fe80 ]] && data=1
done
if [[ -n $2 ]]; then
for i in ${nets[@]}; do
[[ $i == $2 || ${2:0:4} == fe80 ]] && data=$2
[[ $i == $2 || $2 == 0 || ${2:0:4} == fe80 ]] && data=2
done
fi
echo $data
@@ -90,7 +90,7 @@ min6() {
wipe() {
wet=($*)
# remove temporary (privacy extensions) and host ipv6 addresses
for tmp in $(ip -br -6 addr show scope global temporary dev $wet 2>/dev/null|awk '{$1=$2="";print}'); do
for tmp in $(ip -br -6 addr show scope global temporary dev $wet 2>/dev/null|sed -r 's/metric [0-9]+//g'|awk '{$1=$2="";print}'); do
for i in ${!wet[@]}; do
[[ ${wet[$i]} == $tmp || (${wet[$i]} =~ '::' && ${wet[$i]#*/} == 128) ]] && unset 'wet[i]'
done
@@ -107,7 +107,7 @@ show() {
case $# in
1) ip -br addr show scope global to $1 2>/dev/null|awk '{print $1;exit}';;
2) ip -br addr show scope global $1 $2 2>/dev/null|awk '{print $3;exit}';;
3) if [[ $1 == -6 ]]; then main $(ip -br -6 addr show scope global $2 $3 2>/dev/null|awk '{$2="";print;exit}'); else ip -br -4 addr show scope global $2 $3 2>/dev/null|awk '{print $3;exit}'; fi;;
3) if [[ $1 == -6 ]]; then main $(ip -br -6 addr show scope global $2 $3 2>/dev/null|sed -r 's/metric [0-9]+//g'|awk '{$2="";print;exit}'); else ip -br -4 addr show scope global $2 $3 2>/dev/null|awk '{print $3;exit}'; fi;;
esac
}
@@ -195,9 +195,9 @@ check() {
# exclude wireguard VPN docker tunnels
[[ ${net:0:2} == wg && $(grep -Pom1 '^TYPE:1="\K[^"]+' $WIREGUARD/$net.cfg) == 8 ]] && continue
net1=$(sub ${net[1]})
if [[ "avahi show" =~ $CALLER ]]; then
if [[ "avahi show" =~ "$CALLER" ]]; then
[[ -n $net && -n $net1 && -z $(good $net $net1) ]] && bind+=($net)
[[ -n $net1 ]] && ipv4=yes nets+=($net1)
[[ -n $net1 && $net1 != 0 ]] && ipv4=yes nets+=($net1)
else
[[ -n $net1 && -z $(good $net1) ]] && ipv4=yes bind+=($net1)
fi
@@ -211,26 +211,22 @@ check() {
# exclude wireguard VPN docker tunnels
[[ ${net:0:2} == wg && $(grep -Pom1 '^TYPE:1="\K[^"]+' $WIREGUARD/$net.cfg) == 8 ]] && continue
net1=$(sub $(main ${net[@]}))
if [[ "avahi show" =~ $CALLER ]]; then
if [[ "avahi show" =~ "$CALLER" ]]; then
[[ -n $net && -n $net1 && -z $(good $net $net1) ]] && bind+=($net)
[[ -n $net1 ]] && ipv6=yes nets+=($net1)
[[ -n $net1 && $net1 != 0 ]] && ipv6=yes nets+=($net1)
else
[[ -z $deny6 && -n $net1 && -z $(good $net1) ]] && ipv6=yes bind+=($net1)
fi
done <<< $(ip -br -6 addr show scope global|awk '/^(br|bond|eth|wg)[0-9]+(\.[0-9]+)?/{$2="";print}'|sort)
done <<< $(ip -br -6 addr show scope global|sed -r 's/metric [0-9]+//g'|awk '/^(br|bond|eth|wg)[0-9]+(\.[0-9]+)?/{$2="";print}'|sort)
# add loopback interface
if [[ "smb nfs" =~ $CALLER ]]; then
if [[ "smb nfs" =~ "$CALLER" ]]; then
[[ $ipv4 == yes ]] && bind+=(127.0.0.1)
[[ $ipv6 == yes ]] && bind+=(::1)
fi
# add user defined interfaces
if [[ -f $EXTRA ]]; then
. <(/usr/bin/fromdos <$EXTRA)
if [[ "avahi show" =~ $CALLER ]]; then
extra_name
else
extra_addr
fi
. <(fromdos <$EXTRA)
[[ "avahi show" =~ "$CALLER" ]] && extra_name || extra_addr
fi
if [[ $CALLER == ssh ]]; then
# bind stays array

View File

@@ -172,17 +172,23 @@ start_libvirtd() {
echo "no image mounted at /etc/libvirt"
exit 1
fi
# convert libvirt 1.3.1 w/ eric's hyperv vendor id patch to how libvirt does it in libvirt 1.3.3+
sed -ri "s/<vendor id='none'\/>/<vendor_id state='on' value='none'\/>/g" /etc/libvirt/qemu/*.xml &> /dev/null
# remove <locked/> from xml because libvirt + virlogd + virlockd has an issue with locked
sed -ri "s/<locked\/>//g" /etc/libvirt/qemu/*.xml &> /dev/null
# Remove "<watchdog model='itco' action='reset'/>" if reverting from later release.
. /etc/unraid-version
if [[ $(version $version) -le $(version "6.12") ]]; then
sed -ri "/<watchdog model='itco' action='reset'\/>/d" /etc/libvirt/qemu/*.xml &> /dev/null
fi
[[ $(version $version) -le $(version "6.12") ]] && LEGACY=1 || LEGACY=
# update interface section((s) of VM configuration files
for XML in /etc/libvirt/qemu/*.xml; do
[[ -f "$XML" ]] || continue
if grep -qm1 "<vendor_id='none'/>" "$XML"; then
# convert libvirt 1.3.1 w/ eric's hyperv vendor id patch to how libvirt does it in libvirt 1.3.3+
sed -ri "s/<vendor id='none'\/>/<vendor_id state='on' value='none'\/>/g" "$XML"
fi
if grep -qm1 "<locked/>" "$XML"; then
# remove <locked/> from xml because libvirt + virlogd + virlockd has an issue with locked
sed -ri "/<locked\/>/d" "$file"
fi
if [[ -n $LEGACY ]] && grep -qm1 "<watchdog model='itco' action='reset'/>" "$XML"; then
# Remove "<watchdog model='itco' action='reset'/>" if reverting from later release.
sed -ri "/<watchdog model='itco' action='reset'\/>/d" "$XML"
fi
# get all interface sections
ROW=($(grep -nhP '<interface type=' "$XML"|grep -Pom1 '^[0-9]+'))
# get all source sections
@@ -193,13 +199,17 @@ start_libvirtd() {
if [[ ! -e $SYSTEM/$DEV ]]; then
NAME=${DEV//[0-9.]/}
if [[ $NAME == br ]]; then
# change to macvtap
logger -t $(basename $0) "change $DEV to macvtap in $XML"
sed -ri "${ROW[$i]} s/<interface type='bridge'>/<interface type='direct' trustGuestRxFilters='yes'>/; $ROW2 s/<source bridge='$DEV'\/>/<source dev='${DEV/$NAME/vhost}' mode='bridge'\/>/" "$XML"
if grep -qm1 "<interface type='bridge'>" "$XML"; then
# change to macvtap
logger -t $(basename $0) "change $DEV to macvtap in $XML"
sed -ri "${ROW[$i]} s/<interface type='bridge'>/<interface type='direct' trustGuestRxFilters='yes'>/; $ROW2 s/<source bridge='$DEV'\/>/<source dev='${DEV/$NAME/vhost}' mode='bridge'\/>/" "$XML"
fi
else
# change to bridge
logger -t $(basename $0) "change $DEV to bridge in $XML"
sed -ri "${ROW[$i]} s/<interface type='direct'( trustGuestRxFilters='yes')?>/<interface type='bridge'>/; $ROW2 s/<source dev='$DEV' mode='bridge'\/>/<source bridge='${DEV/$NAME/br}'\/>/" "$XML"
if grep -qm1 "<interface type='direct'" "$XML"; then
# change to bridge
logger -t $(basename $0) "change $DEV to bridge in $XML"
sed -ri "${ROW[$i]} s/<interface type='direct'( trustGuestRxFilters='yes')?>/<interface type='bridge'>/; $ROW2 s/<source dev='$DEV' mode='bridge'\/>/<source bridge='${DEV/$NAME/br}'\/>/" "$XML"
fi
fi
fi
done

View File

@@ -10,9 +10,7 @@
# LANNAME 'tower'
# LANMDNS 'tower.local'
# LANFQDN 'lan-ip.hash.myunraid.net' (wildcard cert)
# LANFQDN 'hash.unraid.net' (legacy cert)
# WANFQDN 'wan-ip.hash.myunraid.net' (wildcard cert)
# WANFQDN 'www.hash.unraid.net' (legacy)
# WG0FQDN 'wg0-ip.hash.myunraid.net' (wildcard cert)
CALLER="nginx"
@@ -41,6 +39,12 @@ SERVER_NAMES=()
[[ $PORTSSL != 443 ]] && PORTSSL_URL=":$PORTSSL"
[[ $PORT != 80 ]] && PORT_URL=":$PORT"
# delete legacy unraid.net certificate
if [[ -f $CERTPATH ]]; then
TMPCERTNAME=$(openssl x509 -noout -subject -nameopt multiline -in $CERTPATH | sed -n 's/ *commonName *= //p')
[[ $TMPCERTNAME == *\.unraid\.net ]] && rm $CERTPATH
fi
# if USE_SSL="auto" and no uploaded cert, treat like USE_SSL="no"
[[ $USE_SSL == auto && ! -f $CERTPATH ]] && USE_SSL=no
@@ -252,7 +256,6 @@ build_servers() {
#
# Port settings for https using CA-signed cert
# ex: https://lan-ip.hash.myunraid.net
# ex: https://hash.unraid.net
#
server {
$(listen $PORTSSL ssl http2)
@@ -491,15 +494,7 @@ build_ssl() {
WANIP=$(curl https://wanip4.unraid.net/ 2>/dev/null)
WANIP6=$(curl https://wanip6.unraid.net/ 2>/dev/null)
fi
if [[ $CERTNAME == *\.unraid\.net ]]; then
# legacy LE certificate (only supports IPv4)
LANFQDN=$CERTNAME
SERVER_NAMES+=($LANFQDN)
if [[ -n $WANACCESS && -n $WANIP ]]; then
WANFQDN="www.$CERTNAME"
SERVER_NAMES+=($WANFQDN)
fi
elif [[ $CERTNAME == *\.myunraid\.net ]]; then
if [[ $CERTNAME == *\.myunraid\.net ]]; then
# wildcard LE certificate
[[ -n $LANIP ]] && LANFQDN=$(fqdn $LANIP) SERVER_NAMES+=($LANFQDN)
[[ -n $LANIP6 ]] && LANFQDN6=$(fqdn $LANIP6) SERVER_NAMES+=($LANFQDN6)
@@ -577,6 +572,7 @@ build_ssl() {
}
nginx_status() {
sleep 0.1
[[ -s $PID && -n "$(cat $PID)" && -d "/proc/$(cat $PID)" ]] && return 0 || return 1;
}
@@ -643,6 +639,11 @@ nginx_stop() {
unraid_api_control stop
kill -QUIT $(cat $PID)
wait_nginx_shutdown
if nginx_status; then
echo "Killing Nginx..."
pkill -f $NGINX
wait_nginx_shutdown
fi
fi
}
@@ -675,8 +676,6 @@ nginx_reload() {
if nginx_check; then
echo "Reloading Nginx configuration..."
kill -HUP $(cat $PID)
# update DNS
/usr/bin/php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
sleep 3
else
echo "Invalid configuration, Nginx not reloaded"
@@ -692,8 +691,6 @@ nginx_renew() {
build_ssl
# start unconditionally
$NGINX -c $CONF 2>/dev/null
# update DNS
/usr/bin/php -f /usr/local/emhttp/webGui/include/UpdateDNS.php
}
nginx_update() {

View File

@@ -221,7 +221,7 @@ done
logger -t network "hook services: interface=${interface:-$1}, reason=$reason, protocol=$protocol"
# delayed execution
/usr/local/emhttp/webGui/scripts/update_services 30
/usr/local/emhttp/webGui/scripts/update_services 45
# send update information
if [[ -n $data && -e /var/run/nginx.socket ]]; then
@@ -235,8 +235,8 @@ if [[ -z $interface || "eth0 br0 bond0" =~ $interface ]]; then
# find management interface
[[ -e /sys/class/net/bond0 ]] && dev=bond0 || dev=eth0
[[ -e /sys/class/net/br0 ]] && dev=br0
IPv4=$(ip -br -4 addr show $dev scope global|awk '{print $3;exit}')
IPv6=$(ip -br -6 addr show $dev scope global|awk '{print $NF;exit}')
IPv4=$(ip -br -4 addr show $dev scope global|sed -r 's/ metric [0-9]+//g'|awk '{print $3;exit}')
IPv6=$(ip -br -6 addr show $dev scope global|sed -r 's/ metric [0-9]+//g'|awk '{print $NF;exit}')
[[ -n $IPv4 ]] && echo " IPv4 address: ${IPv4%/*}">>/etc/issue || echo " IPv4 address: not set">>/etc/issue
[[ -n $IPv6 ]] && echo " IPv6 address: ${IPv6%/*}">>/etc/issue || echo " IPv6 address: not set">>/etc/issue
echo >>/etc/issue

View File

@@ -15,7 +15,7 @@ while :; do
# steady state?
subs=$(curl --unix-socket $nginx $status 2>/dev/null|grep -Pom1 'subscribers: \K\d+')
if [[ -z $subs || $subs -eq 0 ]]; then
logger -t monitor "Stop running nchan processes"
# logger -t monitor "Stop running nchan processes"
# kill GUI registered nchan processes
while IFS=$'\n' read -r running; do
pkill -f $docroot/${running/:stop/}

View File

@@ -38,3 +38,5 @@ mkdir -p "$CFG_NEW"
# stating with 6.10 'USE_SSL="auto"' without a LE cert is invalid
[[ ! -f /boot/config/ssl/certs/certificate_bundle.pem ]] && sed -i s/USE_SSL=\"auto\"/USE_SSL=\"no\"/ /boot/config/ident.cfg
# delete any temp dir left over from a version downgrade (see dynamix.plugin.manager/include/Downgrade.php)
rm -rf /boot/deletemedowngrade.*