GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 828c4e...64a81b )
by Charles
02:13
created

IPLoggerService   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 3
dl 0
loc 200
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getIP() 0 6 1
A log() 0 9 1
A getEntries() 0 15 1
B getRule() 0 21 5
A getPastDate() 0 10 1
B checkAllowed() 0 58 6
1
<?php
2
/**
3
 * Provides a central point via which code can log and review events.
4
 * Ideally this service should be injected using SilverStripe's injector.
5
 *
6
 * @package silverstripe-iplogger
7
 * @see https://docs.silverstripe.org/en/3.1/developer_guides/extending/injector/
8
 */
9
class IPLoggerService extends Object
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...
10
{
11
    private static $rules = array();
0 ignored issues
show
Unused Code introduced by
The property $rules is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
12
13
    private static $delete_expired = false;
0 ignored issues
show
Unused Code introduced by
The property $delete_expired is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
14
    
15
    private static $dependencies = array(
0 ignored issues
show
Unused Code introduced by
The property $dependencies is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
16
        'loggerEntry' => '%$IPLoggerEntry',
17
        'banEntry'    => '%$IPBanEntry'
18
    );
19
20
    public $loggerEntry;
21
22
    public $banEntry;
23
24
    public function __construct()
25
    {
26
    }
27
28
    /**
29
     * Returns the IP address of the current client; relies on
30
     * {@link SS_HTTPRequest} to provide the IP address.
31
     *
32
     * @return string The current clients IP address
33
     */
34
    public function getIP()
35
    {
36
        $request = Controller::curr()->getRequest();
37
38
        return $request->getIP();
39
    }
40
41
    /**
42
     * Logs an event against a clients IP address.
43
     *
44
     * @param $event string The event being logged.
45
     */
46
    public function log($event)
47
    {
48
        $entry = $this->loggerEntry;
49
50
        $entry->IP = $this->getIP();
51
        $entry->Event = $event;
52
53
        $entry->write();
54
    }
55
56
    /**
57
     * Get's an array of logs related to the clients IP and the supplied event.
58
     *
59
     * @param string $event The event
60
     * @return DataList A list of logged events
61
     */
62
    public function getEntries($event)
63
    {
64
        $entryClass = get_class($this->loggerEntry);
65
66
        //$this->pruneEntries($event);
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
67
        
68
        $entries = $entryClass::get()->filter(
69
            array(
70
                'Event' => $event,
71
                'IP' => $this->getIP()
72
            )
73
        );
74
75
        return $entries;
76
    }
77
78
    /**
79
     * If a rule exists for a specific event; return it.
80
     *
81
     * Any rules found are checked for validity and an error thrown if incorrect.
82
     * Rules should be defined in .yml config files using the following format.
83
     *
84
     * <code>
85
     * IPLoggerService:
86
     *   rules:
87
     *     submit_contact_form:
88
     *       findtime: 60
89
     *       hits: 4
90
     *       bantime: 600
91
     * </code>
92
     *
93
     * @param string $event The event we want a rule for
94
     * @return array|null The rule array
95
     */
96
    public function getRule($event)
97
    {
98
        $config = $this->config();
99
100
        $rules = $config->get('rules');
101
102
        $rule = null;
103
        
104
        if (isset($rules[$event])) {
105
            $rule = $rules[$event];
106
            
107
            // If the rule for this event is malformed throw an Exception;
108
            if (!(isset($rule['bantime']) && isset($rule['findtime']) && isset($rule['hits']))) {
109
                throw new Exception(
110
                    'Rule must contain the keys bantime, findtime and hits.'
111
                );
112
            }
113
        }
114
115
        return $rule;
116
    }
117
118
    /**
119
     * Get a date x seconds ago.
120
     *
121
     * @param integer $seconds The number of seconds to subtract
122
     * @return DateTime
123
     */
124
    public function getPastDate($seconds)
125
    {
126
        $interval = new DateInterval('PT' . $seconds  . 'S');
127
        $interval->invert = 1;
128
129
        $pastDate = new DateTime();
130
        $pastDate->add($interval);
131
132
        return $pastDate;
133
    }
134
    
135
    /**
136
     * Checks if a specific client IP is allowed to perform an event
137
     *
138
     * First if there is no rule supplied for an event string, we assume
139
     * that user can perform this event as many times as needed and it should
140
     * be logged but not restricted.
141
     * Next a check if performed to see if a client IP has been banned from
142
     * performing an event.
143
     * Finally we calculate the total number of logs for an event and check
144
     * these are within the limits set by the rules. If they are not withing
145
     * the limit apply a ban.
146
     *
147
     * @param string $event The event to check
148
     * @return boolean|string Is the client allowd to perform $event
149
     */
150
    public function checkAllowed($event)
151
    {
152
        $rule = $this->getRule($event);
153
154
        // If no rule is set there must be no limit to how often an event can
155
        // happen.
156
        if (!$rule) {
157
            return true;
158
        }
159
160
        $banClass = get_class($this->banEntry);
161
162
        $filter = array(
163
                'Event'   => $event,
164
                'IP'      => $this->getIP()
165
        );
166
167
        // If a rule has a ban time that is not 0 it means bans expire, so add a
168
        // filter to take this into account.
169
        if ($rule['bantime'] !== 0) {
170
            $maxDate = $this->getPastDate($rule['bantime'])->format('c');
171
            $filter['Created:GreaterThan'] = $maxDate;
172
        }
173
        
174
        $bans = $banClass::get()->filter($filter);
175
176
        // Check if a ban exists.
177
        if ($bans->count() > 0) {
178
            return false;
179
        }
180
181
        $maxDate = $this->getPastDate($rule['findtime'])->format('c');
182
        
183
        $entries = $this->getEntries($event)->filter(
184
            array(
185
                'Created:GreaterThan' => $maxDate
186
            )
187
        );
188
189
        // If there are no log entries the client must not have triggered this
190
        // event before, so let it happen.
191
        if (!$entries) {
192
            return true;
193
        }
194
195
        // Check if the number of entries is greater than the number of hits
196
        // allowed in findtime.
197
        if ($entries->count() > $rule['hits']) {
198
            $banEntry = $this->banEntry;
199
            $banEntry->IP = $this->getIP();
200
            $banEntry->Event = $event;
201
            $banEntry->write();
202
203
            return false;
204
        }
205
206
        return true;
207
    }
208
}
209