Passed
Branch master (54f1b3)
by
unknown
02:56
created

authCheck::init()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 47
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 33
nc 16
nop 3
dl 0
loc 47
rs 8.5125
c 0
b 0
f 0
1
<?php
2
/**
3
 * The MIT License (MIT)
4
 *
5
 * Copyright (c) 2016 Robert Sardinia
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
 */
25
26
27
/**
28
 * Class fileAuthCheck
29
 * @property int nextCheck
30
 */
31
class authCheck
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
32
{
33
34
    /**
35
     * @var
36
     */
37
    private $active;
38
    private $config;
39
    private $discord;
40
    private $logger;
41
    private $db;
42
    private $dbUser;
43
    private $dbPass;
44
    private $dbName;
45
    private $guildID;
46
    private $exempt;
47
    private $corpTickers;
48
    private $nameEnforce;
49
    private $standingsBased;
50
    private $apiKey;
51
    private $authGroups;
52
    private $alertChannel;
53
    private $nameCheck;
54
    private $dbusers;
55
    private $characterCache;
56
    private $corpCache;
57
58
    /**
59
     * @param $config
60
     * @param $discord
61
     * @param $logger
62
     */
63
    public function init($config, $discord, $logger)
64
    {
65
        $this->active = true;
66
        $this->config = $config;
67
        $this->discord = $discord;
68
        $this->logger = $logger;
69
        $this->db = $config['database']['host'];
70
        $this->dbUser = $config['database']['user'];
71
        $this->dbPass = $config['database']['pass'];
72
        $this->dbName = $config['database']['database'];
73
        $this->guildID = $config['bot']['guild'];
74
        $this->exempt = $config['plugins']['auth']['exempt'];
75
        $this->corpTickers = $config['plugins']['auth']['corpTickers'];
76
        $this->nameEnforce = $config['plugins']['auth']['nameEnforce'];
77
        $this->standingsBased = $config['plugins']['auth']['standings']['enabled'];
78
        $this->apiKey = $config['eve']['apiKeys'];
79
        $this->authGroups = $config['plugins']['auth']['authGroups'];
80
        $this->alertChannel = $config['plugins']['auth']['alertChannel'];
81
        $this->nextCheck = 0;
82
        $this->characterCache = array();
83
        $this->corpCache = array();
84
85
        //Set name check to happen if corpTicker or nameEnforce is set
86
        if ($this->nameEnforce === 'true' || $this->corpTickers === 'true') {
87
            $this->nameCheck = true;
88
        }
89
90
        //check if cache has been set
91
        $permsChecked = getPermCache('permsLastChecked');
92
        $namesChecked = getPermCache('nextRename');
93
        if ($namesChecked === NULL) {
94
            setPermCache('nextRename', time());
95
        }
96
97
        //if not set set for now (30 minutes from now for role removal)
98
        if ($permsChecked === NULL) {
99
            setPermCache('permsLastChecked', time() - 1);
100
        }
101
102
        // If config is outdated
103
        if (null === $this->authGroups) {
104
            $msg = '**Auth Failure:** Please update the bots config to the latest version.';
105
            queueMessage($msg, $this->alertChannel, $this->guildID);
106
            $this->logger->addInfo($msg);
107
            $this->active = false;
108
        }
109
    }
110
111
    public function tick()
112
    {
113
        // What was the servers last reported state
114
        $lastStatus = getPermCache('serverState');
115
        if ($this->active && $lastStatus === 'online') {
116
            $permsChecked = getPermCache('permsLastChecked');
117
            $standingsChecked = getPermCache('nextStandingsCheck');
118
119
            if ($permsChecked <= time()) {
120
                $this->logger->addInfo('AuthCheck: Checking for users who have left corp/alliance....');
121
                $this->checkPermissions();
122
                $this->logger->addInfo('AuthCheck: Corp/alliance check complete.');
123
            }
124
125
            if ($this->standingsBased === 'true' && $standingsChecked <= time()) {
126
                $this->logger->addInfo('AuthCheck: Updating Standings');
127
                $this->standingsUpdate();
128
                $this->logger->addInfo('AuthCheck: Standings Updated');
129
            }
130
        }
131
    }
132
133
    // remove user roles
134
    private function removeRoles($member)
135
    {
136
        $discordNick = $member->nick ?: $member->user->username;
137
        $roleRemoved = false;
138
        if (!is_null($member->roles)) {
139
            if (!isset($this->dbusers[$member->id])) {
140
                foreach ($member->roles as $role) {
141
                    if (!in_array($role->name, $this->exempt, true)) {
142
                        $roleRemoved = true;
143
                        $member->removeRole($role);
144
                        $this->discord->guilds->get('id', $this->guildID)->members->save($member);
145
                    }
146
                }
147
            }
148
            if ($roleRemoved) {
149
                $this->logger->addInfo("AuthCheck: Roles removed from $discordNick");
150
                $msg = "Discord roles removed from $discordNick";
151
                queueMessage($msg, $this->alertChannel, $this->guildID);
152
            }
153
        }
154
    }
155
156
    private function getCharacterDetails($charID, $retries = 3)
157
    {
158
        if (isset($this->characterCache[$charID])) {
159
            return $this->characterCache[$charID];
160
        }
161
        $character = null;
162
        for ($i = 0; $i < $retries; $i++) {
163
            $character = characterDetails($charID);
164
            if (!is_null($character)) {
165
                break;
166
            }
167
        }
168
        if (!$character || isset($character['error'])) {
169
            $this->logger->addInfo('AuthCheck: characterDetails lookup failed.');
170
            $msg = isset($character['error']) ? $character['error'] : 'characterDetails lookup failed';
171
            throw new Exception($msg);
172
        }
173
        $this->characterCache[$charID] = $character;
174
        return $character;
175
    }
176
177
    private function getCorpDetails($corpID, $retries = 3)
178
    {
179
        if (isset($this->corpCache[$corpID])) {
180
            return $this->corpCache[$corpID];
181
        }
182
        $corporationDetails = null;
183
        for ($i = 0; $i < $retries; $i++) {
184
            $corporationDetails = corpDetails($corpID);
185
            if (!is_null($corporationDetails)) {
186
                break;
187
            }
188
        }
189
        if (!$corporationDetails || isset($corporationDetails['error'])) {
190
            $this->logger->addInfo('AuthCheck: corpDetails lookup failed.');
191
            $msg = isset($corporationDetails['error']) ? $corporationDetails['error'] : 'corpDetails lookup failed';
192
            throw new Exception($msg);
193
        }
194
        $this->corpCache[$corpID] = $corporationDetails;
195
        return $corporationDetails;
196
    }
197
198
    private function isMemberInValidCorp($member)
199
    {
200
        $corpArray = array_column($this->authGroups, 'corpID');
201
        $discordID = $member->id;
202
        $discordNick = $member->nick ?: $member->user->username;
203
        $return = false;
204
        if (isset($this->dbusers[$discordID])) {
205
            $character = $this->getCharacterDetails($this->dbusers[$discordID]['characterID']);
206
            $return = in_array($character['corporation_id'], $corpArray);
207
        } else {
208
            $this->logger->addInfo("AuthCheck: User [$discordNick] not found in database.");
209
        }
210
        return $return;
211
    }
212
213
    private function isMemberInValidAlliance($member)
214
    {
215
        $allianceArray = array_column($this->authGroups, 'allianceID');
216
        $discordID = $member->id;
217
        $discordNick = $member->nick ?: $member->user->username;
218
        $return = false;
219
        // get charID
220
        if (isset($this->dbusers[$discordID])) {
221
            $character = $this->getCharacterDetails($this->dbusers[$discordID]['characterID']);
222
            $corp = $this->getCorpDetails($character['corporation_id']);
223
            $return = isset($corp['alliance_id']) && in_array($corp['alliance_id'], $allianceArray);
224
        } else {
225
            $this->logger->addInfo("AuthCheck: User [$discordNick] not found in database.");
226
        }
227
        return $return;
228
    }
229
230
    private function isMemberCorpOrAllianceContact($member) {
231
        $return = false;
232
        $discordID = $member->id;
233
        if (isset($this->dbusers[$discordID])) {
234
            $role = $this->dbusers[$discordID]['role'];
235
            if ($role === 'blue' || 'neut' || 'red') {
236
                $character = $this->getCharacterDetails($this->dbusers[$discordID]['characterID']);
237
                $corporationDetails = $this->getCorpDetails($character['corporation_id']);
238
                $allianceContacts = getContacts($corporationDetails['alliance_id']);
239
                $corpContacts = getContacts($character['corporation_id']);
240
                if ($role === 'blue' && ((int) $allianceContacts['standing'] === 5 || 10 || (int) $corpContacts['standing'] === 5 || 10)) {
241
                    $return = true;
242
                }
243
                if ($role === 'red' && ((int) $allianceContacts['standing'] === -5 || -10 || (int) $corpContacts['standing'] === -5 || -10)) {
244
                    $return = true;
245
                }
246
                if ($role === 'neut' && ((int) $allianceContacts['standing'] === 0 || (int) $corpContacts['standing'] === 0 || (@(int) $allianceContacts['standings'] === null || '' && @(int) $corpContacts['standings'] === null || ''))) {
247
                    $return = true;
248
                }
249
            }
250
        }
251
        return $return;
252
    }
253
254
    private function deactivateMember($member)
255
    {
256
        $discordID = $member->id;
257
        $discordNick = $member->nick ?: $member->user->username;
258
        $dbh = new PDO("mysql:host={$this->db};dbname={$this->dbName}", $this->dbUser, $this->dbPass);
259
        $sql = "UPDATE authUsers SET active='no' WHERE discordID='$discordID'";
260
        $dbh->query($sql);
261
        unset($this->dbusers[$member->id])
262
        $this->removeRoles($member);
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_VARIABLE, expecting ';'
Loading history...
263
        $this->logger->addInfo("AuthCheck: {$discordNick} account has been deactivated as they are no longer in a correct corp/alliance.");
264
    }
265
266
    private function resetMemberNick($member)
267
    {
268
        $discordID = $member->id;
269
        $discordNick = $member->nick ?: $member->user->username;
270
        if (!isset($this->dbusers[$discordID])) {
271
            return false;
272
        }
273
        $character = $this->getCharacterDetails($this->dbusers[$discordID]['characterID']); 
274
        $corpTicker = '';
275
        if ($this->corpTickers === 'true') {
276
            $corporationDetails = $this->getCorpDetails($character['corporation_id']);
277
            if ($corporationDetails && isset($corporationDetails['ticker']) && $corporationDetails['ticker'] !== 'U') {
278
                $corpTicker = "[{$corporationDetails['ticker']}] ";
279
            }
280
        }
281
        if ($this->nameEnforce) {
282
            $newNick = $corpTicker . $this->dbusers[$discordID]['eveName'];
283
        } else {
284
            $newNick = $corpTicker . $discordNick;
285
        }
286
        if ($newNick !== $discordNick) {
287
            queueRename($discordID, $newNick, $this->guildID);
288
        }
289
    }
290
291
    /**
292
     * @return null
293
     */
294
295
    //Check user corp/alliance affiliation
296
    //Remove members who have roles but never authed
297
    private function checkPermissions()
298
    {
299
        $this->characterCache = array();
300
        $this->corpCache = array();
301
        // Load database users
302
        $dbh = new PDO("mysql:host={$this->db};dbname={$this->dbName}", $this->dbUser, $this->dbPass);
303
        $this->dbusers = array_column($dbh->query("SELECT discordID, characterID, eveName, role FROM authUsers where active='yes'")->fetchAll(), null, 'discordID');
304
        if (!$this->dbusers) {
305
            return;
306
        }
307
        foreach ($this->discord->guilds->get('id', $this->guildID)->members as $member) {
308
            $discordNick = $member->nick ?: $member->user->username;
309
            if ($this->discord->id == $member->id || $member->getRolesAttribute()->isEmpty()) {
310
                continue;
311
            }
312
            $this->logger->addDebug("AuthCheck: Username: $discordNick");
313
            try {
314
                if (!($this->isMemberInValidCorp($member) || $this->isMemberInValidAlliance($member) || $this->isMemberCorpOrAllianceContact($member))) {
315
                    $this->deactivateMember($member);
316
                }
317
                if ($this->nameCheck) {
318
                    $this->resetMemberNick($member);
319
                }
320
            } catch (Exception $e) {
321
                $this->logger->addError("AuthCheck: " . $e->getMessage());
322
                if ($e->getMessage() == 'The datasource tranquility is temporarily unavailable') {
323
                    return;
324
                }
325
            }
326
        }
327
        setPermCache('permsLastChecked', time() + 1800);
328
    }
329
330
    private function standingsUpdate()
331
    {
332
        foreach ($this->apiKey as $apiKey) {
333
            if ((string) $apiKey['keyID'] === (string) $this->config['plugins']['auth']['standings']['apiKey']) {
334
                $url = "https://api.eveonline.com/char/ContactList.xml.aspx?keyID={$apiKey['keyID']}&vCode={$apiKey['vCode']}&characterID={$apiKey['characterID']}";
335
                $xml = makeApiRequest($url);
336
                if (empty($xml)) {
337
                    return null;
338
                }
339
                foreach ($xml->result->rowset as $contactType) {
340
                    if ((string) $contactType->attributes()->name === 'corporateContactList' || 'allianceContactList') {
341
                        foreach ($contactType->row as $contact) {
342
                            if (null !== $contact['contactID'] && $contact['contactName'] && $contact['standing']) {
343
                                addContactInfo($contact['contactID'], $contact['contactName'], $contact['standing']);
344
                            }
345
                        }
346
                    }
347
                }
348
            }
349
        }
350
        $nextCheck = time() + 86400;
351
        setPermCache('nextStandingsCheck', $nextCheck);
352
    }
353
}
354