Completed
Branch devel-3.0 (330e85)
by Rubén
03:35
created

ApiService::getParamArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * sysPass
4
 *
5
 * @author    nuxsmin
6
 * @link      https://syspass.org
7
 * @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
8
 *
9
 * This file is part of sysPass.
10
 *
11
 * sysPass is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation, either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * sysPass is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 *  along with sysPass.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
namespace SP\Services\Api;
26
27
use Defuse\Crypto\Exception\CryptoException;
28
use SP\Core\Acl\ActionsInterface;
29
use SP\Core\Crypt\Hash;
30
use SP\Core\Crypt\Vault;
31
use SP\Core\Exceptions\InvalidClassException;
32
use SP\DataModel\AuthTokenData;
33
use SP\Modules\Api\Controllers\Help\HelpInterface;
34
use SP\Repositories\Track\TrackRequest;
35
use SP\Services\AuthToken\AuthTokenService;
36
use SP\Services\Service;
37
use SP\Services\ServiceException;
38
use SP\Services\Track\TrackService;
39
use SP\Services\User\UserService;
40
use SP\Services\UserProfile\UserProfileService;
41
use SP\Util\Filter;
42
43
/**
44
 * Class ApiService
45
 *
46
 * @package SP\Services\ApiService
47
 */
48
final class ApiService extends Service
49
{
50
    /**
51
     * @var AuthTokenService
52
     */
53
    private $authTokenService;
54
    /**
55
     * @var TrackService
56
     */
57
    private $trackService;
58
    /**
59
     * @var ApiRequest
60
     */
61
    private $apiRequest;
62
    /**
63
     * @var TrackRequest
64
     */
65
    private $trackRequest;
66
    /**
67
     * @var AuthTokenData
68
     */
69
    private $authTokenData;
70
    /**
71
     * @var HelpInterface
72
     */
73
    private $helpClass;
74
    /**
75
     * @var bool
76
     */
77
    private $initialized = false;
78
79
    /**
80
     * Sets up API
81
     *
82
     * @param $actionId
83
     *
84
     * @throws ServiceException
85
     * @throws \SP\Core\Exceptions\SPException
86
     * @throws \Exception
87
     */
88
    public function setup($actionId)
89
    {
90
        $this->initialized = false;
91
        $this->apiRequest = $this->dic->get(ApiRequest::class);
92
93
        if ($this->trackService->checkTracking($this->trackRequest)) {
94
            $this->addTracking();
95
96
            throw new ServiceException(
97
                __u('Intentos excedidos'),
98
                ServiceException::ERROR,
99
                null,
100
                JsonRpcResponse::INTERNAL_ERROR
101
            );
102
        }
103
104
        $this->authTokenData = $this->authTokenService->getTokenByToken($actionId, $this->getParam('authToken'));
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->authTokenService-...>getParam('authToken')) can also be of type false. However, the property $authTokenData is declared as type SP\DataModel\AuthTokenData. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
105
106
        if ($this->authTokenData->getActionId() !== $actionId) {
107
            $this->accessDenied();
108
        }
109
110
        $this->setupUser();
111
112
        if ($actionId === ActionsInterface::ACCOUNT_VIEW_PASS
113
            || $actionId === ActionsInterface::ACCOUNT_CREATE
114
        ) {
115
            $this->context->setTrasientKey('_masterpass', $this->getMasterPassFromVault());
116
        }
117
118
        $this->initialized = true;
119
    }
120
121
    /**
122
     * Añadir un seguimiento
123
     *
124
     * @throws ServiceException
125
     */
126
    private function addTracking()
127
    {
128
        try {
129
            $this->trackService->add($this->trackRequest);
130
        } catch (\Exception $e) {
131
            throw new ServiceException(
132
                __u('Error interno'),
133
                ServiceException::ERROR,
134
                null,
135
                JsonRpcResponse::INTERNAL_ERROR
136
            );
137
        }
138
    }
139
140
    /**
141
     * Devolver el valor de un parámetro
142
     *
143
     * @param string $param
144
     * @param bool   $required Si es requerido
145
     * @param mixed  $default  Valor por defecto
146
     *
147
     * @return mixed
148
     * @throws ServiceException
149
     */
150
    public function getParam($param, $required = false, $default = null)
151
    {
152
        if ($this->apiRequest === null
153
            || ($required && !$this->apiRequest->exists($param))) {
154
            throw new ServiceException(
155
                __u('Parámetros incorrectos'),
156
                ServiceException::ERROR,
157
                $this->getHelp($this->apiRequest->getMethod()),
0 ignored issues
show
Bug introduced by
$this->getHelp($this->apiRequest->getMethod()) of type array is incompatible with the type string expected by parameter $hint of SP\Services\ServiceException::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

157
                /** @scrutinizer ignore-type */ $this->getHelp($this->apiRequest->getMethod()),
Loading history...
158
                JsonRpcResponse::INVALID_PARAMS
159
            );
160
        }
161
162
        return $this->apiRequest->get($param, $default);
163
    }
164
165
    /**
166
     * Devuelve la ayuda para una acción
167
     *
168
     * @param string $action
169
     *
170
     * @return array
171
     */
172
    public function getHelp($action)
173
    {
174
        if ($this->helpClass !== null) {
175
            return call_user_func([$this->helpClass, 'getHelpFor'], $action);
176
        }
177
178
        return [];
179
    }
180
181
    /**
182
     * @throws ServiceException
183
     */
184
    private function accessDenied()
185
    {
186
        $this->addTracking();
187
188
        throw new ServiceException(
189
            __u('Acceso no permitido'),
190
            ServiceException::ERROR,
191
            null,
192
            JsonRpcResponse::INTERNAL_ERROR
193
        );
194
    }
195
196
    /**
197
     * Sets up user's data in context and performs some user checks
198
     *
199
     * @throws \SP\Core\Exceptions\SPException
200
     */
201
    private function setupUser()
202
    {
203
        $userLoginResponse = UserService::mapUserLoginResponse($this->dic->get(UserService::class)->getById($this->authTokenData->getUserId()));
204
        $userLoginResponse->getIsDisabled() && $this->accessDenied();
205
206
        $this->context->setUserData($userLoginResponse);
207
        $this->context->setUserProfile($this->dic->get(UserProfileService::class)->getById($userLoginResponse->getUserProfileId())->getProfile());
208
    }
209
210
    /**
211
     * Devolver la clave maestra
212
     *
213
     * @return string
214
     * @throws ServiceException
215
     */
216
    private function getMasterPassFromVault()
217
    {
218
        try {
219
            $tokenPass = $this->getParam('tokenPass', true);
220
221
            Hash::checkHashKey($tokenPass, $this->authTokenData->getHash()) || $this->accessDenied();
222
223
            /** @var Vault $vault */
224
            $vault = unserialize($this->authTokenData->getVault());
225
226
            if ($vault && ($pass = $vault->getData($tokenPass . $this->getParam('authToken')))) {
227
                return $pass;
228
            } else {
229
                throw new ServiceException(
230
                    __u('Error interno'),
231
                    ServiceException::ERROR,
232
                    __u('Datos inválidos'),
233
                    JsonRpcResponse::INTERNAL_ERROR
234
                );
235
            }
236
        } catch (CryptoException $e) {
237
            throw new ServiceException(
238
                __u('Error interno'),
239
                ServiceException::ERROR,
240
                $e->getMessage(),
241
                JsonRpcResponse::INTERNAL_ERROR
242
            );
243
        }
244
    }
245
246
    /**
247
     * @param string $param
248
     * @param bool   $required
249
     * @param mixed  $default
250
     *
251
     * @return int
252
     * @throws ServiceException
253
     */
254
    public function getParamInt($param, $required = false, $default = null)
255
    {
256
        return Filter::getInt($this->getParam($param, $required, $default));
257
    }
258
259
    /**
260
     * @param string $param
261
     * @param bool   $required
262
     * @param mixed  $default
263
     *
264
     * @return string
265
     * @throws ServiceException
266
     */
267
    public function getParamString($param, $required = false, $default = null)
268
    {
269
        return Filter::getString($this->getParam($param, $required, $default));
270
    }
271
272
    /**
273
     * @param string $param
274
     * @param bool   $required
275
     * @param mixed  $default
276
     *
277
     * @return array
278
     * @throws ServiceException
279
     */
280
    public function getParamArray($param, $required = false, $default = null)
281
    {
282
        return Filter::getArray($this->getParam($param, $required, $default));
283
    }
284
285
    /**
286
     * @param string $param
287
     * @param bool   $required
288
     * @param mixed  $default
289
     *
290
     * @return int|string
291
     * @throws ServiceException
292
     */
293
    public function getParamEmail($param, $required = false, $default = null)
294
    {
295
        return Filter::getEmail($this->getParam($param, $required, $default));
296
    }
297
298
    /**
299
     * @param string $param
300
     * @param bool   $required
301
     * @param mixed  $default
302
     *
303
     * @return string
304
     * @throws ServiceException
305
     */
306
    public function getParamRaw($param, $required = false, $default = null)
307
    {
308
        return Filter::getRaw($this->getParam($param, $required, $default));
309
    }
310
311
    /**
312
     * @return string
313
     * @throws ServiceException
314
     */
315
    public function getMasterPass()
316
    {
317
        return $this->getMasterKeyFromContext();
318
    }
319
320
    /**
321
     * @param ApiRequest $apiRequest
322
     *
323
     * @return ApiService
324
     */
325
    public function setApiRequest(ApiRequest $apiRequest)
326
    {
327
        $this->apiRequest = $apiRequest;
328
329
        return $this;
330
    }
331
332
    /**
333
     * @return int
334
     */
335
    public function getRequestId()
336
    {
337
        return $this->apiRequest->getId();
338
    }
339
340
    /**
341
     * @return bool
342
     */
343
    public function isInitialized(): bool
344
    {
345
        return $this->initialized;
346
    }
347
348
    /**
349
     * @param string $helpClass
350
     *
351
     * @throws InvalidClassException
352
     */
353
    public function setHelpClass(string $helpClass)
354
    {
355
        if (class_exists($helpClass)) {
356
            $this->helpClass = $helpClass;
0 ignored issues
show
Documentation Bug introduced by
It seems like $helpClass of type string is incompatible with the declared type SP\Modules\Api\Controllers\Help\HelpInterface of property $helpClass.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
357
            return;
358
        }
359
360
        throw new InvalidClassException('Invalid class for helper');
361
    }
362
363
    /**
364
     * @throws \SP\Core\Exceptions\InvalidArgumentException
365
     */
366
    protected function initialize()
367
    {
368
        $this->authTokenService = $this->dic->get(AuthTokenService::class);
369
        $this->trackService = $this->dic->get(TrackService::class);
370
        $this->trackRequest = $this->trackService->getTrackRequest(__CLASS__);
371
    }
372
}