Subversion Repositories oidplus

Rev

Rev 1266 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1000 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
1000 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
1000 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
1131 daniel-mar 26
class OIDplusPageAdminNotifications extends OIDplusPagePluginAdmin
27
        implements INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8 /* getNotifications */
28
{
1000 daniel-mar 29
 
1116 daniel-mar 30
        /**
31
         * @param bool $html
32
         * @return void
33
         */
34
        public function init(bool $html=true) {
1000 daniel-mar 35
        }
36
 
1116 daniel-mar 37
        /**
38
         * @param string $id
39
         * @param array $out
40
         * @param bool $handled
41
         * @return void
42
         * @throws OIDplusException
43
         */
44
        public function gui(string $id, array &$out, bool &$handled) {
1278 daniel-mar 45
                $parts = explode('$',$id,2);
1000 daniel-mar 46
                $id = $parts[0];
1278 daniel-mar 47
                $ra_email = $parts[1] ?? null/*no filter*/;
1000 daniel-mar 48
 
49
                if ($id == 'oidplus:notifications') {
50
                        $handled = true;
51
 
52
                        $out['title'] = _L('Notifications');
53
                        $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
54
 
55
                        if ($ra_email == 'admin') {
56
                                if (!OIDplus::authUtils()->isAdminLoggedIn()) {
1266 daniel-mar 57
                                        throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')), $out['title'], 401);
1000 daniel-mar 58
                                }
59
                        } else if ($ra_email) {
60
                                if (!OIDplus::authUtils()->isRaLoggedIn($ra_email) && !OIDplus::authUtils()->isAdminLoggedIn()) {
1266 daniel-mar 61
                                        throw new OIDplusHtmlException(_L('You need to <a %1>log in</a> as the requested RA %2.',OIDplus::gui()->link('oidplus:login$ra$'.$ra_email),'<b>'.htmlentities($ra_email).'</b>'), $out['title'], 401);
1000 daniel-mar 62
                                }
63
                        } else {
64
                                if ((OIDplus::authUtils()->raNumLoggedIn() == 0) && !OIDplus::authUtils()->isAdminLoggedIn()) {
1266 daniel-mar 65
                                        throw new OIDplusHtmlException(_L('You need to <a %1>log in</a>.',OIDplus::gui()->link('oidplus:login')), $out['title'], 401);
1000 daniel-mar 66
                                }
67
                        }
68
 
69
                        $notifications_by_sev = array();
70
 
1005 daniel-mar 71
                        foreach (OIDplus::getAllPlugins() as $plugin) {
1131 daniel-mar 72
                                if ($plugin instanceof INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8) {
1182 daniel-mar 73
                                        try {
74
                                                $notifications = $plugin->getNotifications($ra_email);
75
                                        } catch (\Exception $e) {
76
                                                $notifications = array(
77
                                                        ['CRIT', _L('The plugin %1 crashed during the notification-check. Message: %2', get_class($plugin), $e->getMessage())]
78
                                                );
79
                                        }
1000 daniel-mar 80
                                        if ($notifications) {
81
                                                foreach ($notifications as $notification) {
1189 daniel-mar 82
                                                        $severity = $notification->getSeverityAsInt();
1000 daniel-mar 83
                                                        if (!isset($notifications_by_sev[$severity])) $notifications_by_sev[$severity] = array();
1189 daniel-mar 84
                                                        $notifications_by_sev[$severity][] = $notification;
1000 daniel-mar 85
                                                }
86
                                        }
87
                                }
88
                        }
89
 
90
                        if (count($notifications_by_sev) == 0) {
91
 
1014 daniel-mar 92
                                $out['text'] .= '<br><p><i>'._L('No notifications').'</i></p>';
1000 daniel-mar 93
 
94
                        } else {
95
                                krsort($notifications_by_sev);
96
 
1189 daniel-mar 97
                                foreach ($notifications_by_sev as $severity => $notifications) {
98
                                        if (count($notifications) == 0) continue;
1000 daniel-mar 99
 
1189 daniel-mar 100
                                        $sev_hf = $notifications[0]->getSeverityAsHumanFriendlyString(true);
1000 daniel-mar 101
 
1189 daniel-mar 102
                                        $out['text'] .= '<h2><span class="severity_'.$severity.'">'.$sev_hf.' ('.count($notifications).')</span></h2>';
1014 daniel-mar 103
                                        $out['text'] .= '<span class="severity_'.$severity.'"><ol>';
1189 daniel-mar 104
                                        foreach ($notifications as $notification) {
1202 daniel-mar 105
                                                assert($notification instanceof OIDplusNotification);
106
                                                $out['text'] .= '<li>'.$notification->getHtmlMessage().'</li>';
1000 daniel-mar 107
                                        }
1014 daniel-mar 108
                                        $out['text'] .= '</ol></span>';
1000 daniel-mar 109
                                }
110
                        }
111
                }
112
        }
113
 
1116 daniel-mar 114
        /**
115
         * @param array $json
116
         * @param string|null $ra_email
117
         * @param bool $nonjs
118
         * @param string $req_goto
119
         * @return bool
120
         * @throws OIDplusException
121
         */
122
        public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool {
1000 daniel-mar 123
                if (!OIDplus::authUtils()->isAdminLoggedIn()) return false;
124
 
125
                if (file_exists(__DIR__.'/img/main_icon16.png')) {
126
                        $tree_icon = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon16.png';
127
                } else {
128
                        $tree_icon = null; // default icon (folder)
129
                }
130
 
131
                $json[] = array(
132
                        'id' => 'oidplus:notifications$admin',
133
                        'icon' => $tree_icon,
134
                        'text' => _L('Notifications')
135
                );
136
 
137
                return true;
138
        }
139
 
1116 daniel-mar 140
        /**
141
         * @param string $request
142
         * @return array|false
143
         */
144
        public function tree_search(string $request) {
1000 daniel-mar 145
                return false;
146
        }
1006 daniel-mar 147
 
1116 daniel-mar 148
        /**
149
         * Checks if the system can be accessed publicly
150
         * Attention! This check does not work if OIDplus is password protected (solution would be to check via JavaScript,
151
         * which is done in setup/), or the URL is in the IntraNet rather than the Internet (only solution would be a
152
         * remote URL check service)
153
         * @param string $dir
154
         * @return false|string
155
         * @throws OIDplusException
156
         */
157
        private function webAccessWorks(string $dir) {
1006 daniel-mar 158
                $url = OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL).$dir;
1182 daniel-mar 159
                $require_ssl = str_starts_with(strtolower($url),'https:');
160
                if (!url_get_contents_available($require_ssl)) return false;
1006 daniel-mar 161
                $access_worked = url_get_contents($url) !== false;
1008 daniel-mar 162
                if ($access_worked) return $url;
1006 daniel-mar 163
 
164
                if (!$access_worked) {
165
                        $url_alt = OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE).$dir;
166
                        if ($url != $url_alt) {
167
                                $access_worked = url_get_contents($url_alt) !== false;
1008 daniel-mar 168
                                if ($access_worked) return $url;
1006 daniel-mar 169
                        }
170
                }
171
 
1008 daniel-mar 172
                return false;
173
        }
174
 
1116 daniel-mar 175
        /**
176
         * @param string $dir
177
         * @return array
178
         * @throws OIDplusException
179
         */
1130 daniel-mar 180
        private function getNotificationsCheckDirAccess(string $dir): array {
1008 daniel-mar 181
                $notifications = array();
182
                if (($url = $this->webAccessWorks($dir)) !== false) {
1006 daniel-mar 183
                        // Re-use message taken from setup/includes/setup_base.js
1189 daniel-mar 184
                        $notifications[] = new OIDplusNotification('CRIT', _L('Attention: The following directory is world-readable: %1 ! You need to configure your web server to restrict access to this directory! (For Apache see <i>.htaccess</i>, for Microsoft IIS see <i>web.config</i>, for Nginx see <i>nginx.conf</i>).','<a target="_blank" href="'.$url.'">'.$dir.'</a>'));
1006 daniel-mar 185
                }
186
                return $notifications;
187
        }
188
 
1116 daniel-mar 189
        /**
1131 daniel-mar 190
         * Implements interface INTF_OID_1_3_6_1_4_1_37476_2_5_2_3_8
1116 daniel-mar 191
         * These are some basic "system" checks, no checks from other plugin. So we add them to our plugin instead.
1130 daniel-mar 192
         * @param string|null $user
1116 daniel-mar 193
         * @return array
194
         * @throws OIDplusException
195
         */
1130 daniel-mar 196
        public function getNotifications(string $user=null): array {
1006 daniel-mar 197
                $notifications = array();
198
                if ((!$user || ($user == 'admin')) && OIDplus::authUtils()->isAdminLoggedIn()) {
199
                        // Check if critical directories are world-readable
1008 daniel-mar 200
                        if ($this->webAccessWorks('index.php') === false) {
1189 daniel-mar 201
                                $notifications[] = new OIDplusNotification('INFO', _L("The system can't check if critical directories (%1) are readable via web-browser. Please verify it manually.", 'userdata, res, dev, includes, setup/includes'));
1008 daniel-mar 202
                        } else {
203
                                // see setup/includes/setup_base.js
204
                                $forbidden_dirs = array(
205
                                        "userdata/index.html",
206
                                        "res/ATTENTION.TXT",
207
                                        "dev/index.html",
208
                                        "includes/index.html",
209
                                        "setup/includes/index.html"
210
                                        //"plugins/viathinksoft/publicPages/100_whois/whois/cli/index.html"
211
                                );
212
                                foreach ($forbidden_dirs as $dir) {
213
                                        $notifications = array_merge($notifications, $this->getNotificationsCheckDirAccess($dir));
214
                                }
1006 daniel-mar 215
                        }
216
 
217
                        // Check if cache directory is writeable
1180 daniel-mar 218
                        $cache_dir = OIDplus::localpath(null).'userdata/cache/';
219
                        if (!is_dir($cache_dir)) {
1189 daniel-mar 220
                                $notifications[] = new OIDplusNotification('ERR', _L('Directory %1 does not exist', $cache_dir));
1180 daniel-mar 221
                        } else if (!isFileOrPathWritable($cache_dir)) {
1189 daniel-mar 222
                                $notifications[] = new OIDplusNotification('ERR', _L('Directory %1 is not writeable. Please check the permissions!', $cache_dir));
1006 daniel-mar 223
                        }
224
                }
225
                return $notifications;
226
        }
227
 
1000 daniel-mar 228
}