Skip to content

Commit b351338

Browse files
author
games647
committed
Allow disabling anti bot completely
1 parent 36c9ae2 commit b351338

File tree

6 files changed

+105
-86
lines changed

6 files changed

+105
-86
lines changed

bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/protocolsupport/ProtocolSupportListener.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.bukkit.entity.Player;
4242
import org.bukkit.event.EventHandler;
4343
import org.bukkit.event.Listener;
44-
4544
import protocolsupport.api.events.ConnectionCloseEvent;
4645
import protocolsupport.api.events.PlayerLoginStartEvent;
4746
import protocolsupport.api.events.PlayerProfileCompleteEvent;
Lines changed: 3 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,7 @@
1-
/*
2-
* SPDX-License-Identifier: MIT
3-
*
4-
* The MIT License (MIT)
5-
*
6-
* Copyright (c) 2015-2021 <Your name and contributors>
7-
*
8-
* Permission is hereby granted, free of charge, to any person obtaining a copy
9-
* of this software and associated documentation files (the "Software"), to deal
10-
* in the Software without restriction, including without limitation the rights
11-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12-
* copies of the Software, and to permit persons to whom the Software is
13-
* furnished to do so, subject to the following conditions:
14-
*
15-
* The above copyright notice and this permission notice shall be included in all
16-
* copies or substantial portions of the Software.
17-
*
18-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24-
* SOFTWARE.
25-
*/
261
package com.github.games647.fastlogin.core;
272

28-
import com.google.common.base.Ticker;
3+
@FunctionalInterface
4+
public interface RateLimiter {
295

30-
import java.util.Arrays;
31-
32-
/**
33-
* Limit the number of requests with a maximum size. Each requests expire after the specified time making it available
34-
* for another request.
35-
*/
36-
public class RateLimiter {
37-
38-
private final Ticker ticker;
39-
40-
private final long[] requests;
41-
private final long expireTime;
42-
private int position;
43-
44-
public RateLimiter(Ticker ticker, int maxLimit, long expireTime) {
45-
this.ticker = ticker;
46-
47-
this.requests = new long[maxLimit];
48-
this.expireTime = expireTime;
49-
50-
// fill the array with expired entry, because nanoTime could overflow and include negative numbers
51-
long nowMilli = ticker.read() / 1_000_000;
52-
long initialVal = nowMilli - expireTime;
53-
Arrays.fill(requests, initialVal);
54-
}
55-
56-
/**
57-
* Ask if access is allowed. If so register the request.
58-
*
59-
* @return true if allowed - false otherwise without any side effects
60-
*/
61-
public boolean tryAcquire() {
62-
// current time millis is not monotonic - it can jump back depending on user choice or NTP
63-
long nowMilli = ticker.read() / 1_000_000;
64-
synchronized (this) {
65-
// having synchronized will limit the amount of concurrency a lot
66-
long oldest = requests[position];
67-
if (nowMilli - oldest >= expireTime) {
68-
requests[position] = nowMilli;
69-
position = (position + 1) % requests.length;
70-
return true;
71-
}
72-
73-
return false;
74-
}
75-
}
6+
boolean tryAcquire();
767
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* SPDX-License-Identifier: MIT
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2015-2021 <Your name and contributors>
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in all
16+
* copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
*/
26+
package com.github.games647.fastlogin.core;
27+
28+
import com.google.common.base.Ticker;
29+
30+
import java.util.Arrays;
31+
32+
/**
33+
* Limit the number of requests with a maximum size. Each requests expire after the specified time making it available
34+
* for another request.
35+
*/
36+
public class TickingRateLimiter implements RateLimiter {
37+
38+
private final Ticker ticker;
39+
40+
private final long[] requests;
41+
private final long expireTime;
42+
private int position;
43+
44+
public TickingRateLimiter(Ticker ticker, int maxLimit, long expireTime) {
45+
this.ticker = ticker;
46+
47+
this.requests = new long[maxLimit];
48+
this.expireTime = expireTime;
49+
50+
// fill the array with expired entry, because nanoTime could overflow and include negative numbers
51+
long nowMilli = ticker.read() / 1_000_000;
52+
long initialVal = nowMilli - expireTime;
53+
Arrays.fill(requests, initialVal);
54+
}
55+
56+
/**
57+
* Ask if access is allowed. If so register the request.
58+
*
59+
* @return true if allowed - false otherwise without any side effects
60+
*/
61+
@Override
62+
public boolean tryAcquire() {
63+
// current time millis is not monotonic - it can jump back depending on user choice or NTP
64+
long nowMilli = ticker.read() / 1_000_000;
65+
synchronized (this) {
66+
// having synchronized will limit the amount of concurrency a lot
67+
long oldest = requests[position];
68+
if (nowMilli - oldest >= expireTime) {
69+
requests[position] = nowMilli;
70+
position = (position + 1) % requests.length;
71+
return true;
72+
}
73+
74+
return false;
75+
}
76+
}
77+
}

core/src/main/java/com/github/games647/fastlogin/core/shared/FastLoginCore.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.github.games647.craftapi.resolver.http.RotatingProxySelector;
3030
import com.github.games647.fastlogin.core.CommonUtil;
3131
import com.github.games647.fastlogin.core.RateLimiter;
32+
import com.github.games647.fastlogin.core.TickingRateLimiter;
3233
import com.github.games647.fastlogin.core.hooks.AuthPlugin;
3334
import com.github.games647.fastlogin.core.hooks.DefaultPasswordGenerator;
3435
import com.github.games647.fastlogin.core.hooks.PasswordGenerator;
@@ -117,13 +118,7 @@ public void load() {
117118
return;
118119
}
119120

120-
int maxCon = config.getInt("anti-bot.connections", 200);
121-
long expireTime = config.getLong("anti-bot.expire", 5) * 60 * 1_000L;
122-
if (expireTime > MAX_EXPIRE_RATE) {
123-
expireTime = MAX_EXPIRE_RATE;
124-
}
125-
126-
rateLimiter = new RateLimiter(Ticker.systemTicker(), maxCon, expireTime);
121+
rateLimiter = createRateLimiter(config.getSection("anti-bot"));
127122
Set<Proxy> proxies = config.getStringList("proxies")
128123
.stream()
129124
.map(HostAndPort::fromString)
@@ -145,6 +140,22 @@ public void load() {
145140
resolver.setOutgoingAddresses(addresses);
146141
}
147142

143+
private RateLimiter createRateLimiter(Configuration botSection) {
144+
boolean enabled = botSection.getBoolean("enabled", true);
145+
if (!enabled) {
146+
// no-op rate limiter
147+
return () -> true;
148+
}
149+
150+
int maxCon = botSection.getInt("anti-bot.connections", 200);
151+
long expireTime = botSection.getLong("anti-bot.expire", 5) * 60 * 1_000L;
152+
if (expireTime > MAX_EXPIRE_RATE) {
153+
expireTime = MAX_EXPIRE_RATE;
154+
}
155+
156+
return new TickingRateLimiter(Ticker.systemTicker(), maxCon, expireTime);
157+
}
158+
148159
private Configuration loadFile(String fileName) throws IOException {
149160
ConfigurationProvider configProvider = ConfigurationProvider.getProvider(YamlConfiguration.class);
150161

core/src/main/resources/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# completely ignore incoming connections. Effectively there will be no database requests and network requests.
1414
# Therefore, auto logins won't be possible.
1515
anti-bot:
16+
enabled: true
1617
# Image the following like bucket. The following is total amount that is allowed in this bucket, while expire
1718
# means how long it takes for every entry to expire.
1819
# Total number of connections

core/src/test/java/com/github/games647/fastlogin/core/RateLimiterTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void allowExpire() throws InterruptedException {
4747
FakeTicker ticker = new FakeTicker(5_000_000L);
4848

4949
// run twice the size to fill it first and then test it
50-
RateLimiter rateLimiter = new RateLimiter(ticker, size, 0);
50+
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, 0);
5151
for (int i = 0; i < size; i++) {
5252
assertTrue("Filling up", rateLimiter.tryAcquire());
5353
}
@@ -65,7 +65,7 @@ public void allowExpireNegative() throws InterruptedException {
6565
FakeTicker ticker = new FakeTicker(-5_000_000L);
6666

6767
// run twice the size to fill it first and then test it
68-
RateLimiter rateLimiter = new RateLimiter(ticker, size, 0);
68+
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, 0);
6969
for (int i = 0; i < size; i++) {
7070
assertTrue("Filling up", rateLimiter.tryAcquire());
7171
}
@@ -86,7 +86,7 @@ public void shouldBlock() {
8686
FakeTicker ticker = new FakeTicker(5_000_000L);
8787

8888
// fill the size
89-
RateLimiter rateLimiter = new RateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
89+
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
9090
for (int i = 0; i < size; i++) {
9191
assertTrue("Filling up", rateLimiter.tryAcquire());
9292
}
@@ -104,7 +104,7 @@ public void shouldBlockNegative() {
104104
FakeTicker ticker = new FakeTicker(-5_000_000L);
105105

106106
// fill the size
107-
RateLimiter rateLimiter = new RateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
107+
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, size, TimeUnit.SECONDS.toMillis(30));
108108
for (int i = 0; i < size; i++) {
109109
assertTrue("Filling up", rateLimiter.tryAcquire());
110110
}
@@ -120,7 +120,7 @@ public void blockedNotAdded() throws InterruptedException {
120120
FakeTicker ticker = new FakeTicker(5_000_000L);
121121

122122
// fill the size - 100ms should be reasonable high
123-
RateLimiter rateLimiter = new RateLimiter(ticker, 1, 100);
123+
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, 1, 100);
124124
assertTrue("Filling up", rateLimiter.tryAcquire());
125125

126126
ticker.add(Duration.ofMillis(50));
@@ -141,7 +141,7 @@ public void blockedNotAddedNegative() throws InterruptedException {
141141
FakeTicker ticker = new FakeTicker(-5_000_000L);
142142

143143
// fill the size - 100ms should be reasonable high
144-
RateLimiter rateLimiter = new RateLimiter(ticker, 1, 100);
144+
TickingRateLimiter rateLimiter = new TickingRateLimiter(ticker, 1, 100);
145145
assertTrue("Filling up", rateLimiter.tryAcquire());
146146

147147
ticker.add(Duration.ofMillis(50));

0 commit comments

Comments
 (0)