Completed
Push — master ( 4db7bf...47f9e5 )
by
unknown
16s queued 13s
created

Auth   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 223
Duplicated Lines 0 %

Test Coverage

Coverage 59.78%

Importance

Changes 9
Bugs 1 Features 4
Metric Value
eloc 117
dl 0
loc 223
ccs 55
cts 92
cp 0.5978
rs 9.2
c 9
b 1
f 4
wmc 40

12 Methods

Rating   Name   Duplication   Size   Complexity  
A signRequest() 0 16 5
A getAccessKey() 0 3 1
A sign() 0 4 1
A signWithData() 0 4 1
A __construct() 0 4 1
F signQiniuAuthorization() 0 66 18
A privateDownloadUrl() 0 14 2
A authorization() 0 4 1
A verifyCallback() 0 4 1
A copyPolicy() 0 11 5
A uploadToken() 0 14 2
A authorizationV2() 0 13 2

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 as $k => $v) {
101
                if (strlen($k) > strlen($keyPrefix) && strpos($k, $keyPrefix) === 0) {
102
                    array_push(
103
                        $headerLines,
104
                        $k . ": " . $v
105
                    );
106
                }
107
            }
108
            if (count($headerLines) > 0) {
109
                $data .= "\n";
110
                sort($headerLines);
111
                $data .= implode("\n", $headerLines);
112
            }
113
        }
114
115
        // append body
116
        $data .= "\n\n";
117
        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

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