Passed
Push — develop ( 5a71b5...d30961 )
by Nikolay
22:52
created

Request::getRequestPriority()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/*
4
 * MikoPBX - free phone system for small business
5
 * Copyright © 2017-2023 Alexey Portnov and Nikolay Beketov
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License along with this program.
18
 * If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
declare(strict_types=1);
22
23
namespace MikoPBX\PBXCoreREST\Http;
24
25
use MikoPBX\AdminCabinet\Controllers\SessionController;
26
use MikoPBX\Common\Providers\AclProvider;
27
use MikoPBX\Common\Providers\ConfigProvider;
28
use MikoPBX\Common\Providers\PBXConfModulesProvider;
29
use MikoPBX\Common\Providers\SessionProvider;
30
use MikoPBX\Modules\Config\RestAPIConfigInterface;
31
use Phalcon\Acl\Enum as AclEnum;
32
use Phalcon\Http\Request as PhRequest;
33
use Phalcon\Mvc\Micro;
34
35
/**
36
 * Class Request
37
 * @package MikoPBX\PBXCoreREST\Http
38
 */
39
class Request extends PhRequest
40
{
41
    /**
42
     * Check the header of a request to understand if it needs async response or not
43
     * @return bool
44
     */
45
    public function isAsyncRequest(): bool
46
    {
47
        return !empty($this->getHeader('X-Async-Response-Channel-Id'));
48
    }
49
50
    /**
51
     * Channel to push request
52
     * @return string
53
     */
54
    public function getAsyncRequestChannelId(): string
55
    {
56
        return $this->getHeader('X-Async-Response-Channel-Id') ?? '';
57
    }
58
59
    /**
60
     * Checks if the current request is a debug request.
61
     *
62
     * This method inspects the presence of the 'X-Debug-The-Request' header
63
     * to determine if the request is for debugging purposes.
64
     *
65
     * @examples
66
     * curl -X POST \
67
     *      -H 'Content-Type: application/json' \
68
     *      -H 'Cookie: XDEBUG_SESSION=PHPSTORM' \
69
     *      -H 'X-Debug-The-Request: 1' \
70
     *      -d '{"filename": "/storage/usbdisk1/mikopbx/tmp/mikopbx-2023.1.223-x86_64.img"}' \
71
     *      http://127.0.0.1/pbxcore/api/system/upgrade
72
     *
73
     * Or add a header at any semantic API request
74
     * ...
75
     *  beforeXHR(xhr) {
76
     *      xhr.setRequestHeader ('X-Debug-The-Request', 1);
77
     *      return xhr;
78
     * },
79
     * ...
80
     *
81
     * @return bool True if the request is a debug request, false otherwise.
82
     */
83
    public function isDebugRequest(): bool
84
    {
85
        return !empty($this->getHeader('X-Debug-The-Request'));
86
    }
87
    /**
88
     * Check if the request is coming from localhost.
89
     *
90
     * @return bool
91
     */
92
    public function isLocalHostRequest(): bool
93
    {
94
        return ($_SERVER['REMOTE_ADDR'] === '127.0.0.1');
95
    }
96
97
    /**
98
     * Requested execution timeout
99
     * @return int
100
     */
101
    public function getRequestTimeout(): int
102
    {
103
        return intval($this->getHeader('X-Processor-Timeout')) ?? 10;
104
    }
105
106
    /**
107
     * Requested execution priority
108
     * @return int
109
     */
110
    public function getRequestPriority(): int
111
    {
112
        return intval($this->getHeader('X-Processor-Priority')) ?? 10;
113
    }
114
115
116
    /**
117
     * Check if debug mode is enabled.
118
     *
119
     * @return bool
120
     */
121
    public function isDebugModeEnabled(): bool
122
    {
123
        return ($this->getDI()->getShared(ConfigProvider::SERVICE_NAME)->path('adminApplication.debugMode'));
124
    }
125
126
    /**
127
     * Check if the request has an authorized session.
128
     *
129
     * @return bool
130
     */
131
    public function isAuthorizedSessionRequest(): bool
132
    {
133
        return $this->getDI()->getShared(SessionProvider::SERVICE_NAME)->has(SessionController::SESSION_ID);
134
    }
135
136
    /**
137
     * Checks current request by ACL lists
138
     *
139
     * For example, we request /pbxcore/api/sip/getPeersStatuses
140
     * We explode the paths on 5-th parts and combine two variables
141
     *  controller = /pbxcore/api/sip
142
     *  action = getPeersStatuses
143
     *
144
     * The next we request the ACL table and check if it allows or not
145
     *
146
     * @param $api
147
     * @return bool
148
     */
149
    public function isAllowedAction($api): bool
150
    {
151
        $pattern = $api->router->getMatches()[0] ?? '';
152
        $partsOfPattern = explode('/', $pattern);
153
        if (count($partsOfPattern) === 5) {
154
            $role = $api->getSharedService(SessionProvider::SERVICE_NAME)->get(SessionController::SESSION_ID)[SessionController::ROLE] ?? AclProvider::ROLE_GUESTS;
155
            $acl =  $api->getSharedService(AclProvider::SERVICE_NAME);
156
            $controller = "/$partsOfPattern[1]/$partsOfPattern[2]/$partsOfPattern[3]";
157
            $action = "/$partsOfPattern[4]";
158
            $allowed = $acl->isAllowed($role, $controller, $action);
159
            if ($allowed != AclEnum::ALLOW) {
160
                return false;
161
            }
162
        }
163
        return true;
164
    }
165
166
    /**
167
     * Checks additional modules routes access rules
168
     * @param Micro $api
169
     *
170
     * @return bool
171
     */
172
    public function thisIsModuleNoAuthRequest(Micro $api): bool
173
    {
174
        $pattern  = $api->request->getURI(true);
175
        $additionalRoutes = PBXConfModulesProvider::hookModulesMethod(RestAPIConfigInterface::GET_PBXCORE_REST_ADDITIONAL_ROUTES);
176
        foreach ($additionalRoutes as $additionalRoutesFromModule) {
177
            foreach ($additionalRoutesFromModule as $additionalRoute) {
178
                $noAuth = $additionalRoute[5] ?? false;
179
                // Let's prepare a regular expression to check the URI
180
                $resultPattern = '/^' . str_replace('/', '\/', $additionalRoute[2]) . '/';
181
                $resultPattern = preg_replace('/\{[^\/]+\}/', '[^\/]+', $resultPattern);
182
                // Let's check the URI
183
                if ($noAuth === true && preg_match($resultPattern, $pattern)) {
184
                    // Allow request without authentication
185
                    return true;
186
                }
187
            }
188
        }
189
        return false;
190
    }
191
}
192