Issues (19)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Client.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 * This file is part of the slince/smartqq package.
4
 *
5
 * (c) Slince <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Slince\SmartQQ;
12
13
use GuzzleHttp\Client as HttpClient;
14
use GuzzleHttp\Psr7\Request as HttpRequest;
15
use GuzzleHttp\Psr7\Response as HttpResponse;
16
use Slince\EventDispatcher\Dispatcher;
17
use Slince\EventDispatcher\DispatcherInterface;
18
use Slince\SmartQQ\Exception\InvalidArgumentException;
19
use Slince\SmartQQ\Message\Request\FriendMessage;
20
use Slince\SmartQQ\Message\Request\GroupMessage;
21
use Slince\SmartQQ\Message\Request\Message as RequestMessage;
22
use Slince\SmartQQ\Message\Response\Message as ResponseMessage;
23
24
class Client
25
{
26
    /**
27
     * 客户端id(固定值).
28
     *
29
     * @var int
30
     */
31
    public static $clientId = 53999199;
32
33
    /**
34
     * @var Credential
35
     */
36
    protected $credential;
37
38
    /**
39
     * @var HttpClient
40
     */
41
    protected $httpClient;
42
43
    /**
44
     * @var DispatcherInterface
45
     */
46
    protected $eventDispatcher;
47
48
    /**
49
     * @var MessageHandler
50
     */
51
    protected $messageHandler;
52
53
    public function __construct(
54
        Credential $credential = null,
55
        HttpClient $httpClient = null,
56
        DispatcherInterface $eventDispatcher = null
57
    ) {
58
        if (!is_null($credential)) {
59
            $this->setCredential($credential);
60
        }
61
        if (is_null($httpClient)) {
62
            $httpClient = new HttpClient([
63
                'verify' => false,
64
            ]);
65
        }
66
        if (is_null($eventDispatcher)) {
67
            $eventDispatcher = new Dispatcher();
68
        }
69
        $this->httpClient = $httpClient;
70
        $this->eventDispatcher = $eventDispatcher;
71
    }
72
73
    /**
74
     * 开启登录流程自行获取凭证
75
     *
76
     * @param string|callable $callback 二维码图片位置|或者自定义处理器
77
     *
78
     * @return Credential
79
     */
80
    public function login($callback)
81
    {
82
        // 兼容二维码位置传参
83
        if (is_string($callback)) {
84
            /* @deprecated 后面会废除此用法,建议传闭包自己处理二维码 */
85
            $callback = function ($qrcode) use ($callback) {
86
                Utils::getFilesystem()->dumpFile($callback, $qrcode);
87
            };
88
        }
89
90
        $resolver = new CredentialResolver($this);
91
        // 进行授权流程,确认授权
92
        $resolver->resolve($callback);
93
        // 等待授权验证成功
94
        $credential = $resolver->wait();
95
        $this->setCredential($credential);
96
        //获取在线状态避免103
97
        $this->getFriendsOnlineStatus();
98
99
        return $credential;
100
    }
101
102
    /**
103
     * 设置凭据.
104
     *
105
     * @param Credential $credential
106
     */
107
    public function setCredential(Credential $credential)
108
    {
109
        $this->credential = $credential;
110
    }
111
112
    /**
113
     * 获取正在使用的凭据.
114
     *
115
     * @return Credential
116
     */
117
    public function getCredential()
118
    {
119
        if (!$this->credential) {
120
            throw new InvalidArgumentException('Please login first or set a credential');
121
        }
122
123
        return $this->credential;
124
    }
125
126
    /**
127
     * 设置 http 请求客户端.
128
     *
129
     * @param HttpClient $httpClient
130
     */
131
    public function setHttpClient($httpClient)
132
    {
133
        $this->httpClient = $httpClient;
134
    }
135
136
    /**
137
     * 获取 http 客户端.
138
     *
139
     * @return HttpClient
140
     */
141
    public function getHttpClient()
142
    {
143
        return $this->httpClient;
144
    }
145
146
    /**
147
     * 获取事件处理器.
148
     *
149
     * @return DispatcherInterface
150
     */
151
    public function getEventDispatcher()
152
    {
153
        return $this->eventDispatcher;
154
    }
155
156
    /**
157
     * 获取所有的群.
158
     *
159
     * @return EntityCollection
160
     */
161
    public function getGroups()
162
    {
163
        $request = new Request\GetGroupsRequest($this->getCredential());
164
        $response = $this->sendRequest($request);
165
166
        return Request\GetGroupsRequest::parseResponse($response);
167
    }
168
169
    /**
170
     * 获取群详细信息.
171
     *
172
     * @param Entity\Group $group
173
     *
174
     * @return Entity\GroupDetail
175
     */
176
    public function getGroupDetail(Entity\Group $group)
177
    {
178
        $request = new Request\GetGroupDetailRequest($group, $this->getCredential());
179
        $response = $this->sendRequest($request);
180
181
        return Request\GetGroupDetailRequest::parseResponse($response);
182
    }
183
184
    /**
185
     * 获取所有讨论组.
186
     *
187
     * @return EntityCollection
188
     */
189
    public function getDiscusses()
190
    {
191
        $request = new Request\GetDiscussesRequest($this->getCredential());
192
        $response = $this->sendRequest($request);
193
194
        return Request\GetDiscussesRequest::parseResponse($response);
195
    }
196
197
    /**
198
     * 获取讨论组详情.
199
     *
200
     * @param Entity\Discuss $discuss
201
     *
202
     * @return Entity\DiscussDetail
203
     */
204
    public function getDiscussDetail(Entity\Discuss $discuss)
205
    {
206
        $request = new Request\GetDiscussDetailRequest($discuss, $this->getCredential());
207
        $response = $this->sendRequest($request);
208
209
        return Request\GetDiscussDetailRequest::parseResponse($response);
210
    }
211
212
    /**
213
     * 获取所有的好友.
214
     *
215
     * @return EntityCollection|Entity\Friend[]
216
     */
217
    public function getFriends()
218
    {
219
        $request = new Request\GetFriendsRequest($this->getCredential());
220
        $response = $this->sendRequest($request);
221
222
        return Request\GetFriendsRequest::parseResponse($response);
223
    }
224
225
    /**
226
     * 获取好友的详细信息.
227
     *
228
     * @param Entity\Friend $friend
229
     *
230
     * @return Entity\Profile
231
     */
232
    public function getFriendDetail(Entity\Friend $friend)
233
    {
234
        $request = new Request\GetFriendDetailRequest($friend, $this->getCredential());
235
        $response = $this->sendRequest($request);
236
237
        return Request\GetFriendDetailRequest::parseResponse($response);
238
    }
239
240
    /**
241
     * 获取好友的QQ号.
242
     *
243
     * @param Entity\Friend $friend
244
     *
245
     * @return int
246
     *
247
     * @deprecated 此接口 Smartqq 官方已经不再提供
248
     */
249
    public function getFriendQQ(Entity\Friend $friend)
250
    {
251
        @trigger_error('The api is not supported now', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
252
253
        $request = new Request\GetQQRequest($friend, $this->getCredential());
254
        $response = $this->sendRequest($request);
255
        $qq = Request\GetQQRequest::parseResponse($response);
256
        $friend->setQq($qq);
257
258
        return $qq;
259
    }
260
261
    /**
262
     * 获取好友的个性签名.
263
     *
264
     * @param Entity\Friend $friend
265
     *
266
     * @return string
267
     */
268
    public function getFriendLnick(Entity\Friend $friend)
269
    {
270
        $request = new Request\GetLnickRequest($friend, $this->getCredential());
271
        $response = $this->sendRequest($request);
272
273
        return Request\GetLnickRequest::parseResponse($response, $friend);
274
    }
275
276
    /**
277
     * 获取好友在线状态
278
     *
279
     * @return EntityCollection
280
     */
281
    public function getFriendsOnlineStatus()
282
    {
283
        $request = new Request\GetFriendsOnlineStatusRequest($this->getCredential());
284
        $response = $this->sendRequest($request);
285
286
        return Request\GetFriendsOnlineStatusRequest::parseResponse($response);
287
    }
288
289
    /**
290
     * 获取最近的会话.
291
     *
292
     * @return EntityCollection|Entity\Recent[]
293
     */
294
    public function getRecentList()
295
    {
296
        $request = new Request\GetRecentListRequest($this->getCredential());
297
        $response = $this->sendRequest($request);
298
299
        return Request\GetRecentListRequest::parseResponse($response);
300
    }
301
302
    /**
303
     * 获取当前登录用户信息.
304
     *
305
     * @return Entity\Profile
306
     */
307
    public function getCurrentUserInfo()
308
    {
309
        $request = new Request\GetCurrentUserRequest();
310
        $response = $this->sendRequest($request);
311
312
        return Request\GetCurrentUserRequest::parseResponse($response);
313
    }
314
315
    /**
316
     * 轮询消息,
317
     * client并不会组装信息,只是将接口返回的信息完整抽象并返回
318
     * 如果需要查询信息对应的数据,如发送人、发送群,请自行获取.
319
     *
320
     * @return ResponseMessage[]
321
     */
322
    public function pollMessages()
323
    {
324
        $request = new Request\PollMessagesRequest($this->getCredential());
325
        $response = $this->sendRequest($request);
326
327
        return Request\PollMessagesRequest::parseResponse($response);
328
    }
329
330
    /**
331
     * 获取 Message handler.
332
     *
333
     * @return MessageHandler
334
     */
335
    public function getMessageHandler()
336
    {
337
        if (null !== $this->messageHandler) {
338
            return $this->messageHandler;
339
        }
340
341
        return $this->messageHandler = new MessageHandler($this);
342
    }
343
344
    /**
345
     * 发送消息,包括好友消息,群消息,讨论组消息.
346
     *
347
     * @param RequestMessage $message
348
     *
349
     * @return bool
350
     */
351
    public function sendMessage(RequestMessage $message)
352
    {
353
        if ($message instanceof FriendMessage) {
354
            $request = new Request\SendFriendMessageRequest($message, $this->getCredential());
355
        } elseif ($message instanceof GroupMessage) {
356
            $request = new Request\SendGroupMessageRequest($message, $this->getCredential());
357
        } else {
358
            $request = new Request\SendDiscusMessageRequest($message, $this->getCredential());
0 ignored issues
show
$message of type object<Slince\SmartQQ\Message\Request\Message> is not a sub-type of object<Slince\SmartQQ\Me...Request\DiscussMessage>. It seems like you assume a child class of the class Slince\SmartQQ\Message\Request\Message to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
359
        }
360
        $response = $this->sendRequest($request);
361
362
        return Request\SendMessageRequest::parseResponse($response);
363
    }
364
365
    /**
366
     * 发送请求
367
     *
368
     * @param Request\RequestInterface $request
369
     * @param array                    $options
370
     *
371
     * @return HttpResponse
372
     */
373
    public function sendRequest(Request\RequestInterface $request, array $options = [])
374
    {
375
        // cookies 必须启用,如果不设置则使用当前凭证的cookie.
376
        if (!isset($options['cookies']) && $this->credential) {
377
            $options['cookies'] = $this->credential->getCookies();
378
        }
379
        if ($parameters = $request->getParameters()) {
380
            if (Request\RequestInterface::REQUEST_METHOD_GET == $request->getMethod()) {
381
                $options['query'] = $parameters;
382
            } else {
383
                $options['form_params'] = $parameters;
384
            }
385
        }
386
        //如果有referer需要伪造该信息
387
        if ($referer = $request->getReferer()) {
388
            $options['headers'] = [
389
                'Referer' => $referer,
390
            ];
391
        }
392
        $response = $this->httpClient->send(
393
            new HttpRequest($request->getMethod(), $request->getUri()),
394
            $options
395
        );
396
397
        return $response;
398
    }
399
}
400