Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic map captcha check to verification #118

Merged
merged 29 commits into from
Dec 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
45c0d0f
feat: change field type "encodedFlags" of Abilities packet to int
jonesdevelopment Nov 28, 2023
5ba58ac
feat: add MapData packet
jonesdevelopment Nov 28, 2023
99ce686
feat: implement map captcha state
jonesdevelopment Nov 28, 2023
edf8fd6
feat: [wip] implement simple map captcha
jonesdevelopment Nov 28, 2023
b540cb5
feat: cache captcha spawn position packet
jonesdevelopment Nov 28, 2023
6412a99
feat: add a chat message when you verify and enter the captcha
jonesdevelopment Nov 28, 2023
14d7922
fix: Chat packet error on 1.7
jonesdevelopment Nov 28, 2023
8e24a71
feat: make map prepared amount and dictionary customizable
jonesdevelopment Nov 28, 2023
45bbbd5
fix: SetSlot packet error on 1.7
jonesdevelopment Nov 28, 2023
8e865fd
fix: make map data work on 1.7
jonesdevelopment Nov 28, 2023
1b0aca6
feat: randomize font size & font style
jonesdevelopment Nov 28, 2023
ad7c0d8
fix: implement KeepAlive during captcha and add timer
jonesdevelopment Nov 28, 2023
7bf807e
feat: add color and x/y randomization to map captcha
jonesdevelopment Nov 28, 2023
3869608
feat: add green and red color palette
jonesdevelopment Nov 28, 2023
1568b7f
feat: implement captcha validation
jonesdevelopment Nov 28, 2023
99c8c27
fix: chat packet not working on 1.7-1.18.2
jonesdevelopment Nov 29, 2023
1657627
fix: only draw important used pixels
jonesdevelopment Nov 29, 2023
4d9199d
feat: optimize color palette
jonesdevelopment Nov 30, 2023
531d6fc
feat: set map image dimensions to 86x86
jonesdevelopment Nov 30, 2023
4d05976
feat: set background color of image to white/light gray
jonesdevelopment Nov 30, 2023
284fae3
feat: recode map info preparing and map data packet sending
jonesdevelopment Nov 30, 2023
90a2d79
fix: x/y offset for 1.8+ in map info
jonesdevelopment Nov 30, 2023
d42d904
fix: add prefix to translated messages for the map captcha
jonesdevelopment Nov 30, 2023
c70b879
feat: make some map captcha options changeable
jonesdevelopment Nov 30, 2023
065bf1a
fix: set the default font size to the average (instead of max)
jonesdevelopment Nov 30, 2023
fb8b285
fix: Chat packet not working on 1.17-1.18.1
jonesdevelopment Dec 2, 2023
558a54a
fix: only send DefaultSpawnPosition to >=1.18.2 clients
jonesdevelopment Dec 2, 2023
158129f
fix: return if captcha is correct to prevent further code execution
jonesdevelopment Dec 2, 2023
cfc489c
feat: cache dynamic DefaultSpawnPosition packet
jonesdevelopment Dec 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,49 @@ public static final class Verification {
private Timing timing;

@Getter
@RequiredArgsConstructor
public enum Timing {
ALWAYS, DURING_ATTACK, NEVER
}

private boolean checkGravity;
private final Map map = new Map();
private final Gravity gravity = new Gravity();

@Getter
public static final class Map {
private boolean enabled;
private boolean drawBackgroundNoise;
private boolean randomizePositions;
private boolean randomizeFontSize;
private int precomputeAmount;
private int maxDuration;
private int maxTries;
private String dictionary;
private Component enterCode;
private Component failedCaptcha;
private String enterCodeActionBar;
}

@Getter
public static final class Gravity {
private boolean enabled;
private Gamemode gamemode;
private int maxMovementTicks;
private int maxIgnoredTicks;
private Component youAreBeingChecked;

@Getter
@RequiredArgsConstructor
public enum Gamemode {
SURVIVAL(0),
CREATIVE(1),
ADVENTURE(2),
// Keep this for backwards compatibility
SPECTATOR(2);

private final int id;
}
}

private boolean logConnections;
private boolean logDuringAttack;
private boolean debugXYZPositions;
Expand All @@ -115,22 +152,7 @@ public enum Timing {
private String successLog;
private String blacklistLog;

private Gamemode gamemode;

@Getter
@RequiredArgsConstructor
public enum Gamemode {
SURVIVAL(0),
CREATIVE(1),
ADVENTURE(2),
SPECTATOR(3);

private final int id;
}

private int maxBrandLength;
private int maxMovementTicks;
private int maxIgnoredTicks;
private int maxLoginPackets;
private int maxPing;
private int readTimeout;
Expand Down Expand Up @@ -413,17 +435,60 @@ public void load() {
+ LINE_SEPARATOR + "All predicted motions are precalculated in order to save performance");
generalConfig.getYaml().setComment("verification.checks.gravity.enabled",
"Should Sonar check for valid client gravity? (Recommended)");
verification.checkGravity = generalConfig.getBoolean("verification.checks.gravity.enabled", true);
verification.gravity.enabled = generalConfig.getBoolean("verification.checks.gravity.enabled", true);

generalConfig.getYaml().setComment("verification.checks.gravity.max-movement-ticks",
"Maximum number of ticks the player has to fall in order to be allowed to hit the platform");
verification.maxMovementTicks = clamp(generalConfig.getInt("verification.checks.gravity.max-movement-ticks", 8),
verification.gravity.maxMovementTicks = clamp(generalConfig.getInt("verification.checks.gravity.max-movement-ticks", 8),
2, 100);

generalConfig.getYaml().setComment("verification.checks.gravity.max-ignored-ticks",
"Maximum number of ignored Y movement changes before a player fails verification");
verification.maxIgnoredTicks = clamp(generalConfig.getInt("verification.checks.gravity.max-ignored-ticks", 5), 1,
128);
verification.gravity.maxIgnoredTicks = clamp(generalConfig.getInt("verification.checks.gravity.max-ignored-ticks", 5),
1, 128);

generalConfig.getYaml().setComment("verification.checks.gravity.gamemode",
"The gamemode of the player during verification"
+ LINE_SEPARATOR + "Possible types: SURVIVAL, CREATIVE, ADVENTURE, SPECTATOR"
+ LINE_SEPARATOR + "- SURVIVAL: all UI components are visible"
+ LINE_SEPARATOR + "- CREATIVE: health and hunger are hidden"
+ LINE_SEPARATOR + "- ADVENTURE: all UI components are visible");
verification.gravity.gamemode = Verification.Gravity.Gamemode.valueOf(
generalConfig.getString("verification.checks.gravity.gamemode", Verification.Gravity.Gamemode.ADVENTURE.name()).toUpperCase());

generalConfig.getYaml().setComment("verification.checks.map-captcha",
"Make the player type a code from a virtual map in chat after the gravity check");
generalConfig.getYaml().setComment("verification.checks.map-captcha.enabled",
"Should Sonar make the player pass a captcha?");
verification.map.enabled = generalConfig.getBoolean("verification.checks.map-captcha.enabled", false);

generalConfig.getYaml().setComment("verification.checks.map-captcha.background-noise",
"Should Sonar draw a white/light gray rectangle behind the captcha?");
verification.map.drawBackgroundNoise = generalConfig.getBoolean("verification.checks.map-captcha.background-noise", true);

generalConfig.getYaml().setComment("verification.checks.map-captcha.random-position",
"Should Sonar randomize the X and Y position of the captcha?");
verification.map.randomizePositions = generalConfig.getBoolean("verification.checks.map-captcha.random-position", true);

generalConfig.getYaml().setComment("verification.checks.map-captcha.random-font-size",
"Should Sonar randomize the size of the font used for rendering the captcha?");
verification.map.randomizeFontSize = generalConfig.getBoolean("verification.checks.map-captcha.random-font-size", true);

generalConfig.getYaml().setComment("verification.checks.map-captcha.precompute",
"How many answers should Sonar precompute (prepare)?");
verification.map.precomputeAmount = generalConfig.getInt("verification.checks.map-captcha.precompute", 10000);

generalConfig.getYaml().setComment("verification.checks.map-captcha.max-duration",
"How long should Sonar wait until the player fails the captcha?");
verification.map.maxDuration = generalConfig.getInt("verification.checks.map-captcha.max-duration", 45000);

generalConfig.getYaml().setComment("verification.checks.map-captcha.max-tries",
"How many times must a player fail the captcha before failing the verification?");
verification.map.maxTries = generalConfig.getInt("verification.checks.map-captcha.max-tries", 3);

generalConfig.getYaml().setComment("verification.checks.map-captcha.dictionary",
"Characters (letters and numbers) that are allowed to appear in the answer to the captcha");
verification.map.dictionary = generalConfig.getString("verification.checks.map-captcha.dictionary", "123456789");

generalConfig.getYaml().setComment("verification.checks.valid-name-regex",
"Regex for validating usernames during verification");
Expand Down Expand Up @@ -452,16 +517,6 @@ public void load() {
"Maximum number of login packets the player has to send in order to be kicked");
verification.maxLoginPackets = clamp(generalConfig.getInt("verification.checks.max-login-packets", 256), 128, 8192);

generalConfig.getYaml().setComment("verification.gamemode",
"The gamemode of the player during verification"
+ LINE_SEPARATOR + "Possible types: SURVIVAL, CREATIVE, ADVENTURE, SPECTATOR"
+ LINE_SEPARATOR + "- SURVIVAL: all UI components are visible"
+ LINE_SEPARATOR + "- CREATIVE: health and hunger are hidden"
+ LINE_SEPARATOR + "- ADVENTURE: all UI components are visible"
+ LINE_SEPARATOR + "- SPECTATOR: all UI components are hidden (Recommended)");
verification.gamemode = Verification.Gamemode.valueOf(
generalConfig.getString("verification.gamemode", Verification.Gamemode.SPECTATOR.name()).toUpperCase());

generalConfig.getYaml().setComment("verification.log-connections",
"Should Sonar log new verification attempts?");
verification.logConnections = generalConfig.getBoolean("verification.log-connections", true);
Expand Down Expand Up @@ -883,6 +938,25 @@ public void load() {
verification.successLog = formatString(messagesConfig.getString("verification.logs.successful",
"%name% has been verified successfully (%time%s!)."));

messagesConfig.getYaml().setComment("verification.welcome",
"Message that is shown to the player when they are being checked for valid gravity");
verification.gravity.youAreBeingChecked = deserialize(formatString(messagesConfig.getString("verification.welcome",
"%prefix%<gray>Please wait a moment for the verification to finish...")));

messagesConfig.getYaml().setComment("verification.captcha.enter-code",
"Message that is shown to the player when they have to enter the answer to the captcha");
verification.map.enterCode = deserialize(formatString(messagesConfig.getString("verification.captcha.enter-code",
"%prefix%<green>Please enter the code in chat that is displayed on the map.")));
messagesConfig.getYaml().setComment("verification.captcha.action-bar",
"Timer that is shown to the player when they have to enter the answer to the captcha"
+ LINE_SEPARATOR + "(Set this to '' to disable the action bar message)");
verification.map.enterCodeActionBar = formatString(messagesConfig.getString("verification.captcha.action-bar",
"%prefix%<green>You have %time-left% seconds left to enter the code in chat"));
messagesConfig.getYaml().setComment("verification.captcha.incorrect",
"Message that is shown to the player when they enter the wrong answer in chat");
verification.map.failedCaptcha = deserialize(formatString(messagesConfig.getString("verification.captcha.incorrect",
"%prefix%<red>You have entered the wrong code. Please try again.")));

messagesConfig.getYaml().setComment("verification.too-many-players",
"Disconnect message that is shown when too many players are verifying at the same time");
verification.tooManyPlayers = deserialize(fromList(messagesConfig.getStringList("verification.too-many-players",
Expand Down
Loading