Subversion Repositories oidplus

Rev

Rev 1086 | Rev 1130 | Go to most recent revision | 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
 
1000 daniel-mar 26
class OIDplusPageAdminNotifications extends OIDplusPagePluginAdmin {
27
 
1116 daniel-mar 28
        /**
29
         * @param bool $html
30
         * @return void
31
         */
32
        public function init(bool $html=true) {
1000 daniel-mar 33
        }
34
 
1116 daniel-mar 35
        /**
36
         * @param string $id
37
         * @param array $out
38
         * @param bool $handled
39
         * @return void
40
         * @throws OIDplusException
41
         */
42
        public function gui(string $id, array &$out, bool &$handled) {
1000 daniel-mar 43
                $parts = explode('$',$id);
44
                $id = $parts[0];
45
 
46
                if ($id == 'oidplus:notifications') {
47
                        $handled = true;
48
                        $ra_email = isset($parts[1]) ? $parts[1] : null/*no filter*/;
49
 
50
                        $out['title'] = _L('Notifications');
51
                        $out['icon'] = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
52
 
53
                        if ($ra_email == 'admin') {
54
                                if (!OIDplus::authUtils()->isAdminLoggedIn()) {
55
                                        $out['icon'] = 'img/error.png';
56
                                        $out['text'] = '<p>'._L('You need to <a %1>log in</a> as administrator.',OIDplus::gui()->link('oidplus:login$admin')).'</p>';
57
                                        return;
58
                                }
59
                        } else if ($ra_email) {
60
                                if (!OIDplus::authUtils()->isRaLoggedIn($ra_email) && !OIDplus::authUtils()->isAdminLoggedIn()) {
61
                                        $out['icon'] = 'img/error.png';
62
                                        $out['text'] = '<p>'._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>').'</p>';
63
                                        return;
64
                                }
65
                        } else {
66
                                if ((OIDplus::authUtils()->raNumLoggedIn() == 0) && !OIDplus::authUtils()->isAdminLoggedIn()) {
67
                                        $out['icon'] = 'img/error.png';
68
                                        $out['text'] = '<p>'._L('You need to <a %1>log in</a>.',OIDplus::gui()->link('oidplus:login')).'</p>';
69
                                        return;
70
                                }
71
                        }
72
 
73
                        $notifications_by_sev = array();
74
 
1005 daniel-mar 75
                        foreach (OIDplus::getAllPlugins() as $plugin) {
1000 daniel-mar 76
                                if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.8')) {
1116 daniel-mar 77
                                        $notifications = $plugin->getNotifications($ra_email); /** @phpstan-ignore-line */
1000 daniel-mar 78
                                        if ($notifications) {
79
                                                foreach ($notifications as $notification) {
80
                                                        list($severity, $htmlMessage) = $notification;
81
 
82
                                                        // Same severities as the log plugin (also same CSS classes)
83
                                                        if ($severity == 'OK')   $severity = 1; // (this makes no sense)
84
                                                        if ($severity == 'INFO') $severity = 2;
85
                                                        if ($severity == 'WARN') $severity = 3;
86
                                                        if ($severity == 'ERR')  $severity = 4;
87
                                                        if ($severity == 'CRIT') $severity = 5;
88
 
89
                                                        if (!isset($notifications_by_sev[$severity])) $notifications_by_sev[$severity] = array();
90
                                                        $notifications_by_sev[$severity][] = $htmlMessage;
91
                                                }
92
                                        }
93
                                }
94
                        }
95
 
96
                        if (count($notifications_by_sev) == 0) {
97
 
1014 daniel-mar 98
                                $out['text'] .= '<br><p><i>'._L('No notifications').'</i></p>';
1000 daniel-mar 99
 
100
                        } else {
101
                                krsort($notifications_by_sev);
102
 
103
                                foreach ($notifications_by_sev as $severity => $htmlMessages) {
1014 daniel-mar 104
                                        if (count($htmlMessages) == 0) continue;
1000 daniel-mar 105
 
106
                                        if ($severity == 1) $sev_hf = _L('OK');
107
                                        else if ($severity == 2) $sev_hf = _L('Informational');
108
                                        else if ($severity == 3) $sev_hf = _L('Warnings');
109
                                        else if ($severity == 4) $sev_hf = _L('Errors');
110
                                        else if ($severity == 5) $sev_hf = _L('Critical issues');
111
                                        else $sev_hf = _L('Severity %1', $severity-1);
112
 
1014 daniel-mar 113
                                        $out['text'] .= '<h2><span class="severity_'.$severity.'">'.$sev_hf.' ('.count($htmlMessages).')</span></h2>';
114
                                        $out['text'] .= '<span class="severity_'.$severity.'"><ol>';
1000 daniel-mar 115
                                        foreach ($htmlMessages as $htmlMessage) {
1014 daniel-mar 116
                                                $out['text'] .= '<li>'.$htmlMessage.'</li>';
1000 daniel-mar 117
                                        }
1014 daniel-mar 118
                                        $out['text'] .= '</ol></span>';
1000 daniel-mar 119
                                }
120
                        }
121
                }
122
        }
123
 
1116 daniel-mar 124
        /**
125
         * @param array $json
126
         * @param string|null $ra_email
127
         * @param bool $nonjs
128
         * @param string $req_goto
129
         * @return bool
130
         * @throws OIDplusException
131
         */
132
        public function tree(array &$json, string $ra_email=null, bool $nonjs=false, string $req_goto=''): bool {
1000 daniel-mar 133
                if (!OIDplus::authUtils()->isAdminLoggedIn()) return false;
134
 
135
                if (file_exists(__DIR__.'/img/main_icon16.png')) {
136
                        $tree_icon = OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon16.png';
137
                } else {
138
                        $tree_icon = null; // default icon (folder)
139
                }
140
 
141
                $json[] = array(
142
                        'id' => 'oidplus:notifications$admin',
143
                        'icon' => $tree_icon,
144
                        'text' => _L('Notifications')
145
                );
146
 
147
                return true;
148
        }
149
 
1116 daniel-mar 150
        /**
151
         * @param string $request
152
         * @return array|false
153
         */
154
        public function tree_search(string $request) {
1000 daniel-mar 155
                return false;
156
        }
1006 daniel-mar 157
 
1116 daniel-mar 158
        /**
159
         * @param string $id
160
         * @return bool
161
         */
162
        public function implementsFeature(string $id): bool {
1006 daniel-mar 163
                if (strtolower($id) == '1.3.6.1.4.1.37476.2.5.2.3.8') return true; // getNotifications()
164
                return false;
165
        }
166
 
1116 daniel-mar 167
        /**
168
         * Checks if the system can be accessed publicly
169
         * Attention! This check does not work if OIDplus is password protected (solution would be to check via JavaScript,
170
         * which is done in setup/), or the URL is in the IntraNet rather than the Internet (only solution would be a
171
         * remote URL check service)
172
         * @param string $dir
173
         * @return false|string
174
         * @throws OIDplusException
175
         */
176
        private function webAccessWorks(string $dir) {
1006 daniel-mar 177
                $url = OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE_CANONICAL).$dir;
178
                $access_worked = url_get_contents($url) !== false;
1008 daniel-mar 179
                if ($access_worked) return $url;
1006 daniel-mar 180
 
181
                if (!$access_worked) {
182
                        $url_alt = OIDplus::webpath(null,OIDplus::PATH_ABSOLUTE).$dir;
183
                        if ($url != $url_alt) {
184
                                $access_worked = url_get_contents($url_alt) !== false;
1008 daniel-mar 185
                                if ($access_worked) return $url;
1006 daniel-mar 186
                        }
187
                }
188
 
1008 daniel-mar 189
                return false;
190
        }
191
 
1116 daniel-mar 192
        /**
193
         * @param string $dir
194
         * @return array
195
         * @throws OIDplusException
196
         */
197
        private function getNotificationsCheckDirAccess(string $dir) {
1008 daniel-mar 198
                $notifications = array();
199
                if (($url = $this->webAccessWorks($dir)) !== false) {
1006 daniel-mar 200
                        // Re-use message taken from setup/includes/setup_base.js
201
                        $msg = _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>');
202
                        $notifications[] = array('CRIT', $msg);
203
                }
204
                return $notifications;
205
        }
206
 
1116 daniel-mar 207
        /**
208
         * Implements interface 1.3.6.1.4.1.37476.2.5.2.3.8
209
         * These are some basic "system" checks, no checks from other plugin. So we add them to our plugin instead.
210
         * @param $user
211
         * @return array
212
         * @throws OIDplusException
213
         */
1006 daniel-mar 214
        public function getNotifications($user=null): array {
215
                $notifications = array();
216
                if ((!$user || ($user == 'admin')) && OIDplus::authUtils()->isAdminLoggedIn()) {
217
                        // Check if critical directories are world-readable
1008 daniel-mar 218
                        if ($this->webAccessWorks('index.php') === false) {
219
                                $notifications[] = array('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'));
220
                        } else {
221
                                // see setup/includes/setup_base.js
222
                                $forbidden_dirs = array(
223
                                        "userdata/index.html",
224
                                        "res/ATTENTION.TXT",
225
                                        "dev/index.html",
226
                                        "includes/index.html",
227
                                        "setup/includes/index.html"
228
                                        //"plugins/viathinksoft/publicPages/100_whois/whois/cli/index.html"
229
                                );
230
                                foreach ($forbidden_dirs as $dir) {
231
                                        $notifications = array_merge($notifications, $this->getNotificationsCheckDirAccess($dir));
232
                                }
1006 daniel-mar 233
                        }
234
 
235
                        // Check if cache directory is writeable
236
                        if (!is_writeable(OIDplus::localpath(null).'userdata/cache/')) {
1007 daniel-mar 237
                                $notifications[] = array('ERR', _L('Directory %1 is not writeable. Please check the permissions!', 'userdata/cache/'));
1006 daniel-mar 238
                        }
239
                }
240
                return $notifications;
241
        }
242
 
1000 daniel-mar 243
}