ShopifyAuthAuthenticate::implementedEvents()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 7
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * CakePHPify : CakePHP Plugin for Shopify API Authentication
4
 * Copyright (c) Multidimension.al (http://multidimension.al)
5
 * Github : https://github.com/multidimension-al/cakephpify
6
 *
7
 * Licensed under The MIT License
8
 * For full copyright and license information, please see the LICENSE file
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @copyright (c) Multidimension.al (http://multidimension.al)
12
 * @link      https://github.com/multidimension-al/cakephpify CakePHPify Github
13
 * @license   http://www.opensource.org/licenses/mit-license.php MIT License
14
 */
15
16
namespace Multidimensional\Cakephpify\Auth;
17
18
use Cake\Auth\BaseAuthenticate;
19
use Cake\Controller\ComponentRegistry;
20
use Cake\Core\Configure;
21
use Cake\Network\Request;
22
use Cake\Network\Response;
23
use Cake\Network\Session;
24
use Cake\Routing\Router;
25
use Multidimensional\Cakephpify\Auth\Event;
26
27
class ShopifyAuthAuthenticate extends BaseAuthenticate
28
{
29
30
    public $apiKey;
31
    private $shopifyApi;
32
    private $shopifyDatabase;
33
34
    /**
35
     * @param registry $registry
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
36
     * @param array    $config
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
37
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
38
     */
39
    public function __construct($registry, array $config = [])
40
    {
41
        parent::__construct($registry, $config);
42
43
        $this->apiKey = isset($config['apiKey']) ? $config['apiKey'] : '';
44
45
        if (empty($this->apiKey)) {
46
            $controller = $this->_registry->getController();
47
48
            if (isset($controller->request->apiKey)) {
49
                $this->apiKey = $controller->request->apiKey;
50
            }
51
        }
52
53
        $this->shopifyApi = $registry->load(
54
            'Multidimensional/Cakephpify.ShopifyAPI',
55
            [
56
            'apiKey' => $this->apiKey
57
            ]
58
        );
59
60
        $this->shopifyDatabase = $registry->load('Multidimensional/Cakephpify.ShopifyDatabase');
61
    }
62
63
    /**
64
     * @param Request  $request
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
65
     * @param Response $response
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
66
     * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be array|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
67
     */
68
    public function authenticate(Request $request, Response $response)
69
    {
70
        return $this->getUser($request);
71
    }
72
73
    /**
74
     * @param Request  $request
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
75
     * @param Response $response
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
76
     * @return null|Response
0 ignored issues
show
Documentation introduced by
Should the return type not be null|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
77
     */
78
    public function unauthenticated(Request $request, Response $response)
79
    {
80
        if (isset($request->query['hmac'])
81
            && isset($request->query['shop'])
82
        ) {
83
            return null;
84
        }
85
86
        if (empty($this->apiKey)) {
87
            return null;
88
        }
89
90
        if (!empty($request->session()->read('shopify_access_token_' . $this->apiKey))
91
            && !empty($request->session()->read('shopify_shop_domain_' . $this->apiKey))
92
        ) {
93
            return null;
94
        }
95
96
        $request->session()->delete('shopify_access_token_' . $this->apiKey);
97
        $request->session()->delete('shopify_shop_domain_' . $this->apiKey);
98
99
        return $response->location($this->_generateLoginUrl());
100
    }
101
102
    /**
103
     * @param Request $request
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
104
     * @return array|bool
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array|false.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
105
     */
106
    public function getUser(Request $request)
107
    {
108
        $accessToken = $request->session()->read('shopify_access_token_' . $this->apiKey);
109
        $shopDomain = $request->session()->read('shopify_shop_domain_' . $this->apiKey);
110
111
        if ($shopDomain) {
112
            $this->shopifyApi->setShopDomain($shopDomain);
113
        }
114
115
        if ((isset($request->query['hmac']) && isset($request->query['shop']))
116
            && (!$shopDomain || $request->query['shop'] != $shopDomain)
117
        ) {
118
            $isValid = $this->shopifyApi->validateHMAC($request->query);
119
            if ($isValid) {
120
                $shopDomain = $this->shopifyApi->setShopDomain($request->query['shop']);
121
122
                if (isset($request->query['code'])) {
123
                    $accessToken = $this->shopifyApi->requestAccessToken($shopDomain, $request->query['code']);
124
                } else {
125
                    $accessToken = $this->shopifyDatabase->getAccessTokenFromShopDomain($shopDomain, $this->apiKey);
126
                }
127
            }
128
        }
129
130
        if ($accessToken) {
131
            $this->shopifyApi->setAccessToken($accessToken);
132
            $this->shopifyApi->setShopDomain($shopDomain);
133
134
            $request->session()->write('shopify_access_token_' . $this->apiKey, $accessToken);
135
            $request->session()->write('shopify_shop_domain_' . $this->apiKey, $shopDomain);
136
137
            $shop = $this->shopifyDatabase->getShopDataFromAccessToken($accessToken, $this->apiKey);
138
139
            if ($shop && is_array($shop)) {
140
                return ['id' => $shop['id'], 'username' => $shop['myshopify_domain']];
141
            }
142
        }
143
144
        return false;
145
    }
146
147
    /**
148
     * @param Request $request
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
149
     * @return void
150
     */
151
    protected function _authenticate(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Coding Style introduced by
Protected method name "ShopifyAuthAuthenticate::_authenticate" must not be prefixed with an underscore
Loading history...
152
    {
153
    }
154
155
    /**
156
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
157
     */
158
    public function implementedEvents()
159
    {
160
        return [
161
            'Auth.afterIdentify' => 'afterIdentify',
162
            'Auth.logout' => 'logout'
163
        ];
164
    }
165
166
    /**
167
     * @param Event $event
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
168
     * @param array $user
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
169
     * @return void
170
     */
171
    public function afterIdentify(Event $event, array $user)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $user is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
172
    {
173
    }
174
175
    /**
176
     * @param Event $event
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
177
     * @param array $user
0 ignored issues
show
introduced by
Missing parameter comment
Loading history...
178
     * @return void
179
     */
180
    public function logout(Event $event, array $user)
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $user is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
181
    {
182
        //$request->session()->delete('shopify_access_token_' . $this->apiKey);
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
183
        //$request->session()->delete('shopify_shop_domain_' . $this->apiKey);
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
184
    }
185
186
    /**
187
     * @return Router
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
188
     */
189
    private function _generateLoginUrl()
190
    {
191
        return Router::url(['controller' => 'Install', 'action' => 'index', 'plugin' => 'Multidimensional/Cakephpify']);
192
    }
193
}
194