1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: lenovo |
5
|
|
|
* Date: 6/12/2018 |
6
|
|
|
* Time: 10:31 AM |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace TimSDK\Core; |
10
|
|
|
|
11
|
|
|
use TimSDK\Core\Exceptions\UserSigException; |
12
|
|
|
use TimSDK\Core\Exceptions\OpensslException; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Class TLSSigApi |
16
|
|
|
* @package TimSDK\Service |
17
|
|
|
*/ |
18
|
|
|
class TLSSig |
19
|
|
|
{ |
20
|
|
|
private $private_key = false; |
21
|
|
|
private $public_key = false; |
22
|
|
|
private $appid; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* 设置Appid |
26
|
|
|
* @param type $appid |
|
|
|
|
27
|
|
|
*/ |
28
|
|
|
public function setAppid($appid) |
29
|
|
|
{ |
30
|
|
|
$this->appid = $appid; |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* 设置私钥 如果要生成usersig则需要私钥 |
35
|
|
|
* @param string $private_key 私钥文件内容 |
36
|
|
|
* @return bool 是否成功 |
37
|
|
|
*/ |
38
|
|
|
public function setPrivateKey($private_key) |
39
|
|
|
{ |
40
|
|
|
$this->private_key = openssl_pkey_get_private($private_key); |
41
|
|
|
if ($this->private_key === false) { |
42
|
|
|
throw new OpensslException(openssl_error_string()); |
43
|
|
|
} |
44
|
|
|
return true; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* 设置公钥 如果要验证usersig则需要公钥 |
49
|
|
|
* @param string $public_key 公钥文件内容 |
50
|
|
|
* @return bool 是否成功 |
51
|
|
|
*/ |
52
|
|
|
public function setPublicKey($public_key) |
53
|
|
|
{ |
54
|
|
|
$this->public_key = openssl_pkey_get_public($public_key); |
55
|
|
|
if ($this->public_key === false) { |
56
|
|
|
throw new OpensslException(openssl_error_string()); |
57
|
|
|
} |
58
|
|
|
return true; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* 用于url的base64encode |
63
|
|
|
* '+' => '*', '/' => '-', '=' => '_' |
64
|
|
|
* @param string $string 需要编码的数据 |
65
|
|
|
* @return string 编码后的base64串,失败返回false |
66
|
|
|
*/ |
67
|
|
|
private function base64Encode($string) |
68
|
|
|
{ |
69
|
|
|
static $replace = array('+' => '*', '/' => '-', '=' => '_'); |
70
|
|
|
$base64 = base64_encode($string); |
71
|
|
|
if ($base64 === false) { |
72
|
|
|
throw new OpensslException('base64_encode error'); |
73
|
|
|
} |
74
|
|
|
return str_replace(array_keys($replace), array_values($replace), $base64); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* 用于url的base64decode |
79
|
|
|
* '+' => '*', '/' => '-', '=' => '_' |
80
|
|
|
* @param string $base64 需要解码的base64串 |
81
|
|
|
* @return string 解码后的数据,失败返回false |
82
|
|
|
*/ |
83
|
|
|
private function base64Decode($base64) |
84
|
|
|
{ |
85
|
|
|
static $replace = array('+' => '*', '/' => '-', '=' => '_'); |
86
|
|
|
$string = str_replace(array_values($replace), array_keys($replace), $base64); |
87
|
|
|
$result = base64_decode($string); |
88
|
|
|
if ($result == false) { |
|
|
|
|
89
|
|
|
throw new OpensslException('base64_decode error'); |
90
|
|
|
} |
91
|
|
|
return $result; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* 根据json内容生成需要签名的buf串 |
96
|
|
|
* @param array $json 票据json对象 |
97
|
|
|
* @return string 按标准格式生成的用于签名的字符串 |
98
|
|
|
* 失败时返回false |
99
|
|
|
*/ |
100
|
|
|
private function genSignContent(array $json) |
101
|
|
|
{ |
102
|
|
|
static $members = array( |
103
|
|
|
'TLS.appid_at_3rd', |
104
|
|
|
'TLS.account_type', |
105
|
|
|
'TLS.identifier', |
106
|
|
|
'TLS.sdk_appid', |
107
|
|
|
'TLS.time', |
108
|
|
|
'TLS.expire_after' |
109
|
|
|
); |
110
|
|
|
$content = ''; |
111
|
|
|
foreach ($members as $member) { |
112
|
|
|
if (!isset($json[$member])) { |
113
|
|
|
throw new OpensslException('json need ' . $member); |
114
|
|
|
} |
115
|
|
|
$content .= "{$member}:{$json[$member]}\n"; |
116
|
|
|
} |
117
|
|
|
return $content; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* ECDSA-SHA256签名 |
122
|
|
|
* @param string $data 需要签名的数据 |
123
|
|
|
* @return string 返回签名 失败时返回false |
124
|
|
|
*/ |
125
|
|
|
private function sign($data) |
126
|
|
|
{ |
127
|
|
|
$signature = ''; |
128
|
|
|
if (!openssl_sign($data, $signature, $this->private_key, 'sha256')) { |
|
|
|
|
129
|
|
|
throw new OpensslException(openssl_error_string()); |
130
|
|
|
} |
131
|
|
|
return $signature; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* 验证ECDSA-SHA256签名 |
136
|
|
|
* @param string $data 需要验证的数据原文 |
137
|
|
|
* @param string $sig 需要验证的签名 |
138
|
|
|
* @return int 1验证成功 0验证失败 |
139
|
|
|
*/ |
140
|
|
|
private function verify($data, $sig) |
141
|
|
|
{ |
142
|
|
|
$ret = openssl_verify($data, $sig, $this->public_key, 'sha256'); |
|
|
|
|
143
|
|
|
if ($ret == -1) { |
144
|
|
|
throw new OpensslException(openssl_error_string()); |
145
|
|
|
} |
146
|
|
|
return $ret; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* 生成usersig |
151
|
|
|
* @param string $identifier 用户名 |
152
|
|
|
* @param uint $expire usersig有效期 默认为180天, 180 * 24 * 3600, 单位秒 |
|
|
|
|
153
|
|
|
* @return string 生成的UserSig 失败时为false |
154
|
|
|
*/ |
155
|
|
|
public function genSig($identifier, $expire = 15552000) |
156
|
|
|
{ |
157
|
|
|
$json = array( |
158
|
|
|
'TLS.account_type' => '0', |
159
|
|
|
'TLS.identifier' => (string) $identifier, |
160
|
|
|
'TLS.appid_at_3rd' => '0', |
161
|
|
|
'TLS.sdk_appid' => (string) $this->appid, |
162
|
|
|
'TLS.expire_after' => (string) $expire, |
163
|
|
|
'TLS.version' => '201512300000', |
164
|
|
|
'TLS.time' => (string) time() |
165
|
|
|
); |
166
|
|
|
$err = ''; |
167
|
|
|
$content = $this->genSignContent($json, $err); |
|
|
|
|
168
|
|
|
$signature = $this->sign($content, $err); |
|
|
|
|
169
|
|
|
$json['TLS.sig'] = base64_encode($signature); |
170
|
|
|
if ($json['TLS.sig'] === false) { |
|
|
|
|
171
|
|
|
throw new UserSigException('base64_encode error'); |
172
|
|
|
} |
173
|
|
|
$json_text = json_encode($json); |
174
|
|
|
if ($json_text === false) { |
175
|
|
|
throw new UserSigException('json_encode error'); |
176
|
|
|
} |
177
|
|
|
$compressed = gzcompress($json_text); |
178
|
|
|
if ($compressed === false) { |
179
|
|
|
throw new UserSigException('gzcompress error'); |
180
|
|
|
} |
181
|
|
|
return $this->base64Encode($compressed); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* 验证usersig |
186
|
|
|
* @param type $sig usersig |
187
|
|
|
* @param type $identifier 需要验证用户名 |
188
|
|
|
* @param type $init_time usersig中的生成时间 |
189
|
|
|
* @param type $expire_time usersig中的有效期 如:3600秒 |
190
|
|
|
* @param type $error_msg 失败时的错误信息 |
191
|
|
|
* @return boolean 验证是否成功 |
192
|
|
|
*/ |
193
|
|
|
public function verifySig($sig, $identifier, &$init_time, &$expire_time, &$error_msg) |
194
|
|
|
{ |
195
|
|
|
try { |
196
|
|
|
$error_msg = ''; |
197
|
|
|
$decoded_sig = $this->base64Decode($sig); |
198
|
|
|
$uncompressed_sig = gzuncompress($decoded_sig); |
199
|
|
|
if ($uncompressed_sig === false) { |
200
|
|
|
throw new UserSigException('gzuncompress error'); |
201
|
|
|
} |
202
|
|
|
$json = json_decode($uncompressed_sig); |
203
|
|
|
if ($json == false) { |
204
|
|
|
throw new UserSigException('json_decode error'); |
205
|
|
|
} |
206
|
|
|
$json = (array) $json; |
207
|
|
|
if ($json['TLS.identifier'] !== $identifier) { |
208
|
|
|
throw new UserSigException("identifier error sigid:{$json['TLS.identifier']} id:{$identifier}"); |
209
|
|
|
} |
210
|
|
|
if ($json['TLS.sdk_appid'] != $this->appid) { |
211
|
|
|
throw new UserSigException("appid error sigappid:{$json['TLS.appid']} thisappid:{$this->appid}"); |
212
|
|
|
} |
213
|
|
|
$content = $this->genSignContent($json); |
214
|
|
|
$signature = base64_decode($json['TLS.sig']); |
215
|
|
|
if ($signature == false) { |
|
|
|
|
216
|
|
|
throw new UserSigException('sig json_decode error'); |
217
|
|
|
} |
218
|
|
|
$succ = $this->verify($content, $signature); |
219
|
|
|
if (!$succ) { |
220
|
|
|
throw new UserSigException('verify failed'); |
221
|
|
|
} |
222
|
|
|
$init_time = $json['TLS.time']; |
223
|
|
|
$expire_time = $json['TLS.expire_after']; |
224
|
|
|
return true; |
225
|
|
|
} catch (UserSigException $ex) { |
226
|
|
|
$error_msg = $ex->getMessage(); |
227
|
|
|
return false; |
228
|
|
|
} |
229
|
|
|
} |
230
|
|
|
} |
231
|
|
|
|
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths