Completed
Push — master ( 3bc4a5...384a55 )
by
unknown
11:49 queued 10s
created

AuthService::decrypt()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Slides\Connector\Auth;
4
5
use Illuminate\Encryption\Encrypter;
6
use Illuminate\Support\Arr;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Contracts\Auth\Guard as GuardContract;
9
use Illuminate\Support\Str;
10
use Slides\Connector\Auth\Sync\User as RemoteUser;
11
12
/**
13
 * Class AuthService
14
 *
15
 * @package Slides\Connector\Auth
16
 */
17
class AuthService
18
{
19
    const HANDLER_USER_CREATE      = 'create';
20
    const HANDLER_USER_UPDATE      = 'update';
21
    const HANDLER_USER_DELETE      = 'delete';
22
    const HANDLER_USER_SYNC_CREATE = 'sync.create';
23
    const HANDLER_USER_SYNC_UPDATE = 'sync.update';
24
    const HANDLER_USER_SYNC_DELETE = 'sync.delete';
25
26
    /**
27
     * The class with handler methods
28
     *
29
     * @var object
30
     */
31
    protected $handlersContainer;
32
33
    /**
34
     * HTTP Client
35
     *
36
     * @var Client
37
     */
38
    protected $client;
39
40
    /**
41
     * The authentication guard.
42
     *
43
     * @var TokenGuard
44
     */
45
    protected $guard;
46
47
    /**
48
     * The fallback authentication guard.
49
     *
50
     * @var GuardContract
51
     */
52
    protected $fallbackGuard;
53
54
    /**
55
     * Checks whether a service is disabled
56 10
     *
57
     * @return bool
58 10
     */
59
    public function disabled(): bool
60
    {
61
        return !config('connector.auth.enabled', true);
62
    }
63
64
    /**
65
     * AuthService constructor.
66 17
     *
67
     * @param Client $client
68 17
     */
69 17
    public function __construct(Client $client)
70
    {
71
        $this->client = $client;
72
    }
73
74
    /**
75
     * Authenticate a user.
76
     *
77
     * @param string $email
78
     * @param string $password
79
     * @param bool $remember
80
     *
81
     * @return mixed
82 4
     *
83
     * @throws
84 4
     */
85
    public function login(string $email, string $password, bool $remember = false)
86
    {
87
        if($this->disabled()) {
88 4
            return $this->handleFallback('login', compact('email', 'password', 'remember'));
89
        }
90
91
        return $this->guard->login($email, $password, $remember);
92
    }
93
94
    /**
95
     * Authenticate a user without the password.
96
     *
97
     * Warning! This method has implemented temporarily to make able to login users
98
     * who use Social Auth on 24Templates. MUST NOT be used in any other cases.
99
     *
100
     * @param string $email
101
     * @param bool $remember
102
     *
103
     * @return mixed
104 2
     *
105
     * @throws
106 2
     */
107
    public function unsafeLogin(string $email, bool $remember = false)
108
    {
109
        if($this->disabled()) {
110 2
            return $this->handleFallback('unsafeLogin', compact('email', 'remember'));
111
        }
112
113
        return $this->guard->unsafeLogin($email, $remember);
114
    }
115
116
    /**
117
     * Logout a user.
118
     *
119
     * @return mixed
120
     *
121
     * @throws
122
     */
123
    public function logout()
124
    {
125
        if($this->disabled()) {
126
            return $this->handleFallback('logout');
127
        }
128
129
        $this->guard->logout();
130
131
        return null;
132
    }
133
134
    /**
135
     * Create a remote user.
136
     *
137
     * @param int $userId
138
     * @param string $name
139
     * @param string $email
140
     * @param string $password
141
     * @param string $country
142 2
     *
143
     * @return array
144 2
     */
145
    public function register(int $userId, string $name, string $email, string $password, string $country)
146
    {
147
        if($this->disabled()) {
148 2
            return [];
149
        }
150
151
        return $this->client->request('register', compact('userId', 'name', 'email', 'password', 'country'));
152
    }
153
154
    /**
155
     * Send an email with a password resetting link
156
     *
157
     * @param string $email
158
     *
159
     * @return bool
160 2
     *
161
     * @throws
162 2
     */
163
    public function forgot(string $email)
164
    {
165
        if($this->disabled()) {
166 2
            return $this->handleFallback('forgot', compact('email'));
167
        }
168 2
169
        $this->client->request('forgot', compact('email'));
170
171
        return $this->client->success(true);
172
    }
173
174
    /**
175
     * Checks whether password reset token is valid
176
     *
177
     * @param string $token
178
     * @param string $email
179
     *
180
     * @return string|false
181 2
     *
182
     * @throws
183 2
     */
184
    public function validatePasswordResetToken(string $token, string $email)
185
    {
186
        if($this->disabled()) {
187 2
            return $this->handleFallback('validateReset', compact('token', 'email'));
188
        }
189 2
190 1
        $response = $this->client->request('validateReset', compact('token', 'email'));
191
192
        if(!$this->client->success(true)) {
193 1
            return false;
194
        }
195
196
        return Arr::get($response, 'user.email');
197
    }
198
199
    /**
200
     * Checks whether password reset token is valid
201
     *
202
     * @param string $token
203
     * @param string $email
204
     * @param string $password
205
     * @param string $confirmation
206
     *
207
     * @return array|false
208 2
     *
209
     * @throws
210 2
     */
211
    public function resetPassword(string $token, string $email, string $password, string $confirmation)
212 2
    {
213
        $parameters = compact('token', 'email', 'password', 'confirmation');
214
215
        if($this->disabled()) {
216 2
            return $this->handleFallback('resetPassword', $parameters);
217
        }
218 2
219 1
        $response = $this->client->request('reset', $parameters);
220
221
        if(!$this->client->success(true)) {
222 1
            return false;
223
        }
224
225
        return $response;
226
    }
227
228
    /**
229
     * Update a remote user
230
     *
231
     * @param int $id Local user ID
232
     * @param string|null $name
233
     * @param string|null $email
234
     * @param string|null $password Raw password, in case if changed
235
     * @param string|null $country Two-letter country code.
236 2
     *
237
     * @return array|false
238 2
     */
239
    public function update(int $id, ?string $name, ?string $email, ?string $password, ?string $country)
240
    {
241
        if($this->disabled()) {
242 2
            return false;
243
        }
244 2
245
        $attributes = array_filter(compact('id', 'name', 'email', 'password', 'country'));
246 2
247 1
        $response = $this->client->request('update', compact('id', 'attributes'));
248
249
        if(!$this->client->success(true)) {
250 1
            return false;
251
        }
252
253
        return $response;
254
    }
255
256
    /**
257
     * Safely delete a remote user.
258
     *
259
     * @param int $id Remote user ID.
260
     *
261
     * @return array|false
262
     */
263
    public function delete(int $id)
264
    {
265
        if($this->disabled()) {
266
            return false;
267
        }
268
269
        $response = $this->client->request('delete', compact('id'));
270
271
        if(!$this->client->success(true)) {
272
            return false;
273
        }
274
275
        return $response;
276
    }
277
278
    /**
279
     * Restore a remote user.
280
     *
281
     * @param int $id Remote user ID.
282
     *
283
     * @return array|false
284
     */
285
    public function restore(int $id)
286
    {
287
        if($this->disabled()) {
288
            return false;
289
        }
290
291
        $response = $this->client->request('restore', compact('id'));
292
293
        if(!$this->client->success(true)) {
294
            return false;
295
        }
296
297
        return $response;
298
    }
299
300
    /**
301
     * Retrieve a remote user
302
     *
303
     * @return RemoteUser|null
304
     */
305
    public function retrieveByToken()
306
    {
307
        if($this->disabled()) {
308
            return null;
309
        }
310
311
        try {
312
            $response = $this->client->request('me');
313
        }
314
        catch(\Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException $e) {
315
            return null;
316
        }
317
318
        if(!$this->client->success(true)) {
319
            return null;
320
        }
321
322
        return RemoteUser::createFromResponse($response);
323
    }
324
325
    /**
326
     * Load handlers from the given container.
327
     *
328
     * @param $container
329 17
     *
330
     * @return void
331 17
     */
332 17
    public function loadHandlers($container)
333
    {
334
        $this->handlersContainer = $container;
335
    }
336
337
    /**
338
     * Run a handler
339
     *
340
     * @param string $key
341
     * @param array $parameters
342
     * @param \Closure|null $fallback
343
     *
344
     * @return mixed
345 7
     *
346
     * @throws \Exception
347 7
     */
348
    public function handle(string $key, array $parameters = [], \Closure $fallback = null)
349 7
    {
350 1
        $handler = Str::camel(str_replace('.', ' ', $key));
351
352
        if(!method_exists($this->handlersContainer, $handler)) {
353
            throw new \InvalidArgumentException("Handler `{$handler}` cannot be found");
354 6
        }
355 6
356
        return $this->ensure(function() use ($handler, $parameters) {
357
            return call_user_func_array([$this->handlersContainer, $handler], $parameters);
358
        }, $fallback);
359
    }
360
361
    /**
362
     * Run a fallback handler.
363
     *
364
     * @param string $key
365
     * @param array $parameters
366
     * @param \Closure|null $fallback
367
     *
368
     * @return mixed
369 2
     *
370
     * @throws \Exception
371 2
     */
372 2
    public function handleFallback(string $key, array $parameters = [], \Closure $fallback = null)
373
    {
374 2
        $key = 'fallback' . Str::studly($key);
375
        $parameters = array_merge(['guard' => $this->fallbackGuard], $parameters);
376
377
        return $this->handle($key, $parameters, $fallback);
378
    }
379
380
    /**
381
     * Store/retrieve a parameter from the cache.
382
     *
383
     * @param string $key
384
     * @param mixed $value
385
     *
386
     * @return Cache|void
387
     */
388
    public function cache(string $key = null, $value = null)
389
    {
390
        $cache = new Cache();
391
392
        if(!func_num_args()) {
393
            return $cache;
394
        }
395
396
        if(func_num_args() === 1) {
397
            return $cache->get($key);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type null; however, parameter $key of Slides\Connector\Auth\Cache::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

397
            return $cache->get(/** @scrutinizer ignore-type */ $key);
Loading history...
398
        }
399
400
        $cache->set($key, null, $value);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type null; however, parameter $key of Slides\Connector\Auth\Cache::set() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

400
        $cache->set(/** @scrutinizer ignore-type */ $key, null, $value);
Loading history...
401
    }
402
403
    /**
404
     * Store/retrieve a user's parameter from the cache.
405
     *
406
     * @param int $remoteId The remote user ID.
407
     * @param string|null $key
408
     * @param mixed $value
409
     *
410
     * @return Cache|mixed|void
411
     */
412
    public function userCache(int $remoteId, string $key = null, $value = null)
413
    {
414
        $cache = new Cache();
415
416
        if(func_num_args() === 1) {
417
            return $cache->getUserParams($remoteId);
418
        }
419
420
        if(func_num_args() === 2) {
421
            return $cache->getUserParam($remoteId, $key);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type null; however, parameter $key of Slides\Connector\Auth\Cache::getUserParam() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

421
            return $cache->getUserParam($remoteId, /** @scrutinizer ignore-type */ $key);
Loading history...
422
        }
423
424
        $cache->setUserParam($remoteId, $key, $value);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type null; however, parameter $key of Slides\Connector\Auth\Cache::setUserParam() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

424
        $cache->setUserParam($remoteId, /** @scrutinizer ignore-type */ $key, $value);
Loading history...
425
    }
426
427
    /**
428
     * Performs a callback logic within database transaction.
429
     *
430
     * @param \Closure $callback
431
     * @param \Closure|null $fallback The callback which should fired when exception throws.
432
     *
433
     * @return mixed
434 6
     *
435
     * @throws \Exception
436 6
     */
437
    protected function ensure(\Closure $callback, \Closure $fallback = null)
438
    {
439 6
        DB::beginTransaction();
440
441 3
        try {
442 2
            $output = $callback();
443
        }
444 2
        catch(\Exception $e) {
445
            DB::rollBack();
446
447
            if(is_null($fallback)) {
448 2
                throw $e;
449
            }
450
451 5
            $output = $fallback($e);
452
        }
453 5
454
        DB::commit();
455
456
        return $output;
457
    }
458
459
    /**
460
     * Set authentication guard.
461 17
     *
462
     * @param \Slides\Connector\Auth\TokenGuard $guard
463 17
     */
464 17
    public function setGuard(TokenGuard $guard): void
465
    {
466
        $this->guard = $guard;
467
    }
468
469
    /**
470
     * Set fallback authentication guard.
471
     *
472
     * @param GuardContract $guard
473
     */
474
    public function setFallbackGuard(GuardContract $guard): void
475
    {
476
        $this->fallbackGuard = $guard;
477
    }
478
479
    /**
480
     * Set HTTP Client.
481
     *
482
     * @param Client $client
483
     */
484
    public function setClient(Client $client): void
485
    {
486
        $this->client = $client;
487
    }
488
489
    /**
490
     * Get HTTP client.
491 17
     *
492
     * @return Client
493 17
     */
494
    public function getClient(): Client
495
    {
496
        return $this->client;
497
    }
498
499
    /**
500
     * Encrypt the given value.
501
     *
502
     * @param string $value
503
     *
504
     * @return string
505
     */
506
    public function encrypt(string $value): string
507
    {
508
        return $this->encrypter()->encrypt($value);
509
    }
510
511
    /**
512
     * Decrypt the given value.
513
     *
514
     * @param string $value
515
     *
516
     * @return string
517
     */
518
    public function decrypt(string $value): string
519
    {
520
        return $this->encrypter()->decrypt($value);
521
    }
522
523
    /**
524
     * Retrieve encrypter instance.
525
     *
526
     * @return Encrypter
527
     */
528
    protected function encrypter(): Encrypter
529
    {
530
        if ($key = config('connector.auth.cryptKey')){
531
            throw new \RuntimeException('The crypt key should be provided.');
532
        }
533
534
        return new Encrypter($key);
535
    }
536
}