Passed
Push — devel-3.0 ( 617c3b...e28ec2 )
by Rubén
04:01
created

ApiService::getParamInt()   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
                -32601
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
                -32601
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 int|string
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
                -32602
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
        return call_user_func([$this->helpClass, 'getHelpFor'], $action);
175
    }
176
177
    /**
178
     * @throws ServiceException
179
     */
180
    private function accessDenied()
181
    {
182
        $this->addTracking();
183
184
        throw new ServiceException(
185
            __u('Acceso no permitido'),
186
            ServiceException::ERROR,
187
            null,
188
            -32601
189
        );
190
    }
191
192
    /**
193
     * Sets up user's data in context and performs some user checks
194
     *
195
     * @throws \SP\Core\Exceptions\SPException
196
     */
197
    private function setupUser()
198
    {
199
        $userLoginResponse = UserService::mapUserLoginResponse($this->dic->get(UserService::class)->getById($this->authTokenData->getUserId()));
200
        $userLoginResponse->getIsDisabled() && $this->accessDenied();
201
202
        $this->context->setUserData($userLoginResponse);
203
        $this->context->setUserProfile($this->dic->get(UserProfileService::class)->getById($userLoginResponse->getUserProfileId())->getProfile());
204
    }
205
206
    /**
207
     * Devolver la clave maestra
208
     *
209
     * @return string
210
     * @throws ServiceException
211
     */
212
    private function getMasterPassFromVault()
213
    {
214
        try {
215
            $tokenPass = $this->getParam('tokenPass', true);
216
217
            Hash::checkHashKey($tokenPass, $this->authTokenData->getHash()) || $this->accessDenied();
218
219
            /** @var Vault $vault */
220
            $vault = unserialize($this->authTokenData->getVault());
221
222
            if ($vault && ($pass = $vault->getData($tokenPass . $this->getParam('authToken')))) {
223
                return $pass;
224
            } else {
225
                throw new ServiceException(
226
                    __u('Error interno'),
227
                    ServiceException::ERROR,
228
                    __u('Datos inválidos'),
229
                    -32603
230
                );
231
            }
232
        } catch (CryptoException $e) {
233
            throw new ServiceException(
234
                __u('Error interno'),
235
                ServiceException::ERROR,
236
                $e->getMessage(),
237
                -32603
238
            );
239
        }
240
    }
241
242
    /**
243
     * @param string $param
244
     * @param bool   $required
245
     * @param null   $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
246
     *
247
     * @return int
248
     * @throws ServiceException
249
     */
250
    public function getParamInt($param, $required = false, $default = null)
251
    {
252
        return Filter::getInt($this->getParam($param, $required, $default));
253
    }
254
255
    /**
256
     * @param string $param
257
     * @param bool   $required
258
     * @param null   $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
259
     *
260
     * @return string
261
     * @throws ServiceException
262
     */
263
    public function getParamString($param, $required = false, $default = null)
264
    {
265
        return Filter::getString($this->getParam($param, $required, $default));
266
    }
267
268
    /**
269
     * @param string $param
270
     * @param bool   $required
271
     * @param null   $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
272
     *
273
     * @return int|string
274
     * @throws ServiceException
275
     */
276
    public function getParamEmail($param, $required = false, $default = null)
277
    {
278
        return Filter::getEmail($this->getParam($param, $required, $default));
279
    }
280
281
    /**
282
     * @param string $param
283
     * @param bool   $required
284
     * @param null   $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
285
     *
286
     * @return string
287
     * @throws ServiceException
288
     */
289
    public function getParamRaw($param, $required = false, $default = null)
290
    {
291
        return Filter::getRaw($this->getParam($param, $required, $default));
292
    }
293
294
    /**
295
     * @return string
296
     * @throws ServiceException
297
     */
298
    public function getMasterPass()
299
    {
300
        return $this->getMasterKeyFromContext();
301
    }
302
303
    /**
304
     * @param ApiRequest $apiRequest
305
     *
306
     * @return ApiService
307
     */
308
    public function setApiRequest(ApiRequest $apiRequest)
309
    {
310
        $this->apiRequest = $apiRequest;
311
312
        return $this;
313
    }
314
315
    /**
316
     * @return int
317
     */
318
    public function getRequestId()
319
    {
320
        return $this->apiRequest->getId();
321
    }
322
323
    /**
324
     * @return bool
325
     */
326
    public function isInitialized(): bool
327
    {
328
        return $this->initialized;
329
    }
330
331
    /**
332
     * @param string $helpClass
333
     *
334
     * @throws InvalidClassException
335
     */
336
    public function setHelpClass(string $helpClass)
337
    {
338
        if (class_exists($helpClass)) {
339
            $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...
340
            return;
341
        }
342
343
        throw new InvalidClassException('Invalid class for helper');
344
    }
345
346
    /**
347
     * @throws \SP\Core\Exceptions\InvalidArgumentException
348
     */
349
    protected function initialize()
350
    {
351
        $this->authTokenService = $this->dic->get(AuthTokenService::class);
352
        $this->trackService = $this->dic->get(TrackService::class);
353
        $this->trackRequest = $this->trackService->getTrackRequest(__CLASS__);
354
    }
355
}