Passed
Pull Request — master (#373)
by
unknown
22:11
created

Auth   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 257
Duplicated Lines 0 %

Test Coverage

Coverage 59.78%

Importance

Changes 9
Bugs 1 Features 4
Metric Value
eloc 134
dl 0
loc 257
ccs 55
cts 92
cp 0.5978
rs 8.72
c 9
b 1
f 4
wmc 46

12 Methods

Rating   Name   Duplication   Size   Complexity  
F signQiniuAuthorization() 0 68 19
A privateDownloadUrl() 0 14 2
A signRequest() 0 16 5
A getAccessKey() 0 3 1
A sign() 0 4 1
A authorization() 0 4 1
B authorizationV2() 0 45 7
A signWithData() 0 4 1
A verifyCallback() 0 4 1
A copyPolicy() 0 11 5
A uploadToken() 0 14 2
A __construct() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Auth often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Auth, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Qiniu;
3
4
use Qiniu\Http\Header;
5
use Qiniu\Zone;
6
7
final class Auth
8
{
9
    private $accessKey;
10
    private $secretKey;
11
12
    public function __construct($accessKey, $secretKey)
13
    {
14
        $this->accessKey = $accessKey;
15
        $this->secretKey = $secretKey;
16
    }
17 6
18
    public function getAccessKey()
19 6
    {
20
        return $this->accessKey;
21
    }
22 93
23
    public function sign($data)
24 93
    {
25 93
        $hmac = hash_hmac('sha1', $data, $this->secretKey, true);
26
        return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac);
27
    }
28 24
29
    public function signWithData($data)
30 24
    {
31 24
        $encodedData = \Qiniu\base64_urlSafeEncode($data);
32
        return $this->sign($encodedData) . ':' . $encodedData;
33
    }
34 54
35
    public function signRequest($urlString, $body, $contentType = null)
36 54
    {
37 54
        $url = parse_url($urlString);
38 54
        $data = '';
39 51
        if (array_key_exists('path', $url)) {
40 51
            $data = $url['path'];
41 54
        }
42 9
        if (array_key_exists('query', $url)) {
43 9
            $data .= '?' . $url['query'];
44 54
        }
45
        $data .= "\n";
46 54
47 24
        if ($body !== null && $contentType === 'application/x-www-form-urlencoded') {
48 24
            $data .= $body;
49 54
        }
50
        return $this->sign($data);
51
    }
52
53
    /**
54
     * @param string $urlString
55
     * @param string $method
56
     * @param string $body
57
     * @param null|Header $headers
58 12
     */
59
    public function signQiniuAuthorization($urlString, $method = "GET", $body = "", $headers = null)
60 12
    {
61
        $url = parse_url($urlString);
62 12
        if (!$url) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $url of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
63 12
            return array(null, new \Exception("parse_url error"));
64 9
        }
65 9
66 3
        // append method, path and query
67
        if ($method === "") {
68 12
            $data = "GET ";
69
        } else {
70 12
            $data = $method . " ";
71 12
        }
72
        if (isset($url["path"])) {
73
            $data .= $url["path"];
74 21
        }
75
        if (isset($url["query"])) {
76 21
            $data .= "?" . $url["query"];
77 21
        }
78 21
79 15
        // append Host
80 15
        $data .= "\n";
81
        $data .= "Host: ";
82 21
        if (isset($url["host"])) {
83 21
            $data .= $url["host"];
84 21
        }
85
        if (isset($url["port"]) && $url["port"] > 0) {
86 21
            $data .= ":" . $url["port"];
87 21
        }
88
89
        // try append content type
90
        if ($headers != null && isset($headers["Content-Type"])) {
91
            // append content type
92
            $data .= "\n";
93
            $data .= "Content-Type: " . $headers["Content-Type"];
94
        }
95
96
        // try append xQiniuHeaders
97
        if ($headers != null) {
98
            $headerLines = array();
99
            $keyPrefix = "X-Qiniu-";
100
            foreach ($headers->getRawData() as $k => $vs) {
101
                if (strlen($k) > strlen($keyPrefix) && strpos($k, $keyPrefix) === 0) {
102
                    foreach ($vs as $v) {
103
                        array_push(
104
                            $headerLines,
105
                            $k . ": " . $v
106
                        );
107
                    }
108
                }
109
            }
110
            if (count($headerLines) > 0) {
111
                $data .= "\n";
112
                sort($headerLines);
113
                $data .= implode("\n", $headerLines);
114
            }
115
        }
116
117
        // append body
118
        $data .= "\n\n";
119
        if (count($body) > 0
0 ignored issues
show
Bug introduced by
$body of type string is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

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

119
        if (count(/** @scrutinizer ignore-type */ $body) > 0
Loading history...
120
            && isset($headers["Content-Type"])
121
            && $headers["Content-Type"] != "application/octet-stream"
122 21
        ) {
123
            $data .= $body;
124 21
        }
125 18
126
        return array($this->sign(utf8_encode($data)), null);
127 3
    }
128 3
129 3
    public function verifyCallback($contentType, $originAuthorization, $url, $body)
130 3
    {
131 3
        $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
132 3
        return $originAuthorization === $authorization;
133
    }
134
135 51
    public function privateDownloadUrl($baseUrl, $expires = 3600)
136
    {
137 51
        $deadline = time() + $expires;
138 51
139
        $pos = strpos($baseUrl, '?');
140
        if ($pos !== false) {
141
            $baseUrl .= '&e=';
142
        } else {
143
            $baseUrl .= '?e=';
144
        }
145
        $baseUrl .= $deadline;
146
147
        $token = $this->sign($baseUrl);
148
        return "$baseUrl&token=$token";
149
    }
150
151
    public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true)
152
    {
153
        $deadline = time() + $expires;
154
        $scope = $bucket;
155
        if ($key !== null) {
156
            $scope .= ':' . $key;
157
        }
158
159
        $args = self::copyPolicy($args, $policy, $strictPolicy);
160
        $args['scope'] = $scope;
161
        $args['deadline'] = $deadline;
162
163
        $b = json_encode($args);
164
        return $this->signWithData($b);
165
    }
166
167
    /**
168
     *上传策略,参数规格详见
169
     *http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html
170
     */
171
    private static $policyFields = array(
172
        'callbackUrl',
173
        'callbackBody',
174
        'callbackHost',
175
        'callbackBodyType',
176
        'callbackFetchKey',
177
178
        'returnUrl',
179
        'returnBody',
180
181
        'endUser',
182
        'saveKey',
183
        'forceSaveKey',
184
        'insertOnly',
185
186
        'detectMime',
187
        'mimeLimit',
188
        'fsizeMin',
189
        'fsizeLimit',
190
191
        'persistentOps',
192
        'persistentNotifyUrl',
193
        'persistentPipeline',
194
195
        'deleteAfterDays',
196
        'fileType',
197
        'isPrefixalScope',
198
    );
199
200
    private static function copyPolicy(&$policy, $originPolicy, $strictPolicy)
201
    {
202
        if ($originPolicy === null) {
203
            return array();
204
        }
205
        foreach ($originPolicy as $key => $value) {
206
            if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) {
207
                $policy[$key] = $value;
208
            }
209
        }
210
        return $policy;
211
    }
212
213
    public function authorization($url, $body = null, $contentType = null)
214
    {
215
        $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
216
        return array('Authorization' => $authorization);
217
    }
218
219
    public function authorizationV2($url, $method, $body = null, $contentType = null)
220
    {
221
        $urlItems = parse_url($url);
222
        $host = $urlItems['host'];
223
224
        if (isset($urlItems['port'])) {
225
            $port = $urlItems['port'];
226
        } else {
227
            $port = '';
228
        }
229
230
        $path = $urlItems['path'];
231
        if (isset($urlItems['query'])) {
232
            $query = $urlItems['query'];
233
        } else {
234
            $query = '';
235
        }
236
237
        //write request uri
238
        $toSignStr = $method . ' ' . $path;
239
        if (!empty($query)) {
240
            $toSignStr .= '?' . $query;
241
        }
242
243
        //write host and port
244
        $toSignStr .= "\nHost: " . $host;
245
        if (!empty($port)) {
246
            $toSignStr .= ":" . $port;
247
        }
248
249
        //write content type
250
        if (!empty($contentType)) {
251
            $toSignStr .= "\nContent-Type: " . $contentType;
252
        }
253
254
        $toSignStr .= "\n\n";
255
256
        //write body
257
        if (!empty($body)) {
258
            $toSignStr .= $body;
259
        }
260
261
        $sign = $this->sign($toSignStr);
262
        $auth = 'Qiniu ' . $sign;
263
        return array('Authorization' => $auth);
264
    }
265
}
266