Skip to content

Commit 6832c87

Browse files
Merge pull request #10 from ModGardenEvent/feat/minecraft-oauth
feat: Add Minecraft Account linking endpoints.
2 parents 7138739 + 4635eab commit 6832c87

File tree

10 files changed

+473
-137
lines changed

10 files changed

+473
-137
lines changed

.editorconfig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ trim_trailing_whitespace = true # Gets rid of unnecessary indentation, and IJ ig
1313
# Note: Turn on Smart Tabs!
1414
ij_java_continuation_indent_size = 8 # Should be twice the tab width (8 for 4 columns, 16 for 8)
1515
ij_json_continuation_indent_size = 4 # Should be the tab size
16-
ij_toml_continuation_indent_size = 4 # Should be the tab size
16+
ij_toml_continuation_indent_size = 4 # Should be the tab size
17+
18+
[*.key]
19+
insert_final_newline = false # Don't do this for any publickeys.

src/main/java/net/modgarden/backend/ModGardenBackend.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.io.InputStreamReader;
3636
import java.lang.reflect.Type;
3737
import java.net.http.HttpClient;
38+
import java.security.NoSuchAlgorithmException;
3839
import java.sql.Connection;
3940
import java.sql.DriverManager;
4041
import java.sql.PreparedStatement;
@@ -108,6 +109,7 @@ public static void main(String[] args) {
108109
app.error(422, BackendError::handleError);
109110
app.error(500, BackendError::handleError);
110111
app.start(7070);
112+
111113
LOG.info("Mod Garden Backend Started!");
112114
}
113115

@@ -138,6 +140,7 @@ public static void v1(Javalin app) {
138140

139141
get(app, 1, "discord/oauth/modrinth", DiscordBotOAuthHandler::authModrinthAccount);
140142
get(app, 1, "discord/oauth/minecraft", DiscordBotOAuthHandler::authMinecraftAccount);
143+
get(app, 1, "discord/oauth/minecraft/challenge", DiscordBotOAuthHandler::getMicrosoftCodeChallenge);
141144

142145
post(app, 1, "discord/submission/create/modrinth", DiscordBotSubmissionHandler::submitModrinth);
143146
post(app, 1, "discord/submission/delete", DiscordBotSubmissionHandler::unsubmit);

src/main/java/net/modgarden/backend/handler/v1/discord/DiscordBotLinkHandler.java

Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
11
package net.modgarden.backend.handler.v1.discord;
22

33
import com.mojang.serialization.Codec;
4-
import com.mojang.serialization.JsonOps;
54
import com.mojang.serialization.codecs.RecordCodecBuilder;
65
import io.javalin.http.Context;
76
import net.modgarden.backend.ModGardenBackend;
87
import net.modgarden.backend.data.LinkCode;
98
import net.modgarden.backend.data.profile.User;
10-
import net.modgarden.backend.util.ExtraCodecs;
119

12-
import java.math.BigInteger;
1310
import java.sql.Connection;
1411
import java.sql.ResultSet;
1512
import java.sql.SQLException;
16-
import java.util.ArrayList;
17-
import java.util.List;
1813
import java.util.Locale;
19-
import java.util.UUID;
2014

2115
public class DiscordBotLinkHandler {
2216
public static void link(Context ctx) {
@@ -49,19 +43,20 @@ public static void link(Context ctx) {
4943
deleteStatement.execute();
5044
if (accountId == null) {
5145
ctx.result("Invalid link code for " + capitalisedService + ".");
52-
ctx.status(422);
46+
ctx.status(400);
5347
return;
5448
}
5549

5650
if (body.service.equals(LinkCode.Service.MODRINTH.serializedName())) {
57-
handleModrinth(ctx, connection, body.discordId, accountId, capitalisedService);
51+
handleModrinth(ctx, connection, body.discordId, accountId);
5852
return;
5953
} else if (body.service.equals(LinkCode.Service.MINECRAFT.serializedName())) {
60-
handleMinecraft(ctx, connection, body.discordId, accountId, capitalisedService);
54+
handleMinecraft(ctx, connection, body.discordId, accountId);
55+
DiscordBotOAuthHandler.invalidateFromUuid(body.linkCode);
6156
return;
6257
}
6358
ctx.result("Invalid link code service '" + capitalisedService + "'.");
64-
ctx.status(422);
59+
ctx.status(400);
6560
} catch (SQLException ex) {
6661
ModGardenBackend.LOG.error("Exception in SQL query.", ex);
6762
ctx.result("Internal Error.");
@@ -72,78 +67,66 @@ public static void link(Context ctx) {
7267
private static void handleModrinth(Context ctx,
7368
Connection connection,
7469
String discordId,
75-
String accountId,
76-
String capitalisedService) throws SQLException {
70+
String accountId) throws SQLException {
7771
try (var accountCheckStatement = connection.prepareStatement("SELECT 1 FROM users WHERE modrinth_id = ?");
7872
var userCheckStatement = connection.prepareStatement("SELECT 1 FROM users WHERE discord_id = ? AND modrinth_id IS NOT NULL");
7973
var insertStatement = connection.prepareStatement("UPDATE users SET modrinth_id = ? WHERE discord_id = ?")) {
8074
accountCheckStatement.setString(1, accountId);
8175
ResultSet accountCheckResult = accountCheckStatement.executeQuery();
8276
if (accountCheckResult.isBeforeFirst() && accountCheckResult.getBoolean(1)) {
83-
ctx.result("The specified " + capitalisedService + " account has already been linked to a Mod Garden account.");
84-
ctx.status(422);
77+
ctx.result("The specified Modrinth account has already been linked to a Mod Garden account.");
78+
ctx.status(400);
8579
return;
8680
}
8781

8882
userCheckStatement.setString(1, discordId);
8983
ResultSet userCheckResult = userCheckStatement.executeQuery();
9084
if (userCheckResult.isBeforeFirst() && userCheckResult.getBoolean(1)) {
91-
ctx.result("The specified Mod Garden account is already linked with " + capitalisedService + ".");
92-
ctx.status(422);
85+
ctx.result("The specified Mod Garden account is already linked with Modrinth.");
86+
ctx.status(400);
9387
return;
9488
}
9589

9690
insertStatement.setString(1, accountId);
9791
insertStatement.setString(2, discordId);
9892
insertStatement.execute();
9993

100-
ctx.result("Successfully linked " + capitalisedService + " account to Mod Garden account associated with Discord ID '" + discordId + "'.");
94+
ctx.result("Successfully linked Modrinth account to Mod Garden account associated with Discord ID '" + discordId + "'.");
10195
ctx.status(201);
10296
}
10397
}
10498

10599
private static void handleMinecraft(Context ctx,
106-
Connection connection,
107-
String discordId,
108-
String uuid,
109-
String capitalisedService) throws SQLException {
110-
try (var accountCheckStatement = connection.prepareStatement("SELECT 1 FROM users WHERE instr(minecraft_accounts, ?) > 0");
111-
var insertStatement = connection.prepareStatement("UPDATE users SET minecraft_accounts = ? WHERE discord_id = ?")) {
112-
accountCheckStatement.setString(1, uuid);
113-
ResultSet accountCheckResult = accountCheckStatement.executeQuery();
114-
if (accountCheckResult.isBeforeFirst() && accountCheckResult.getBoolean(1)) {
115-
ctx.result("The specified " + capitalisedService + " account has already been linked to a Mod Garden account.");
116-
ctx.status(422);
117-
return;
118-
}
119-
100+
Connection connection,
101+
String discordId,
102+
String uuid) throws SQLException {
103+
try (var accountCheckStatement = connection.prepareStatement("SELECT user_id FROM minecraft_accounts WHERE uuid = ?");
104+
var insertStatement = connection.prepareStatement("INSERT INTO minecraft_accounts (uuid, user_id) VALUES (?, ?)")) {
120105
User user = User.query(discordId, "discord");
121106
if (user == null) {
122107
ctx.result("Could not find user from Discord ID '" + discordId + "'.");
123-
ctx.status(422);
108+
ctx.status(400);
124109
return;
125110
}
126111

127-
List<UUID> uuids = new ArrayList<>(user.minecraftAccounts());
128-
uuids.add(new UUID(
129-
new BigInteger(uuid.substring(0, 16), 16).longValue(),
130-
new BigInteger(uuid.substring(16), 16).longValue()
131-
));
132-
133-
var dataResult = ExtraCodecs.UUID_CODEC.listOf().encodeStart(JsonOps.INSTANCE, uuids);
134-
135-
if (!dataResult.hasResultOrPartial()) {
136-
ModGardenBackend.LOG.error("Failed to create Minecraft account data. {}", dataResult.error().orElseThrow().message());
137-
ctx.result("Failed to create Minecraft account data.");
138-
ctx.status(500);
112+
accountCheckStatement.setString(1, uuid);
113+
ResultSet accountCheckResult = accountCheckStatement.executeQuery();
114+
if (accountCheckResult.isBeforeFirst() && accountCheckResult.getString(1) != null) {
115+
if (accountCheckResult.getString(1).equals(user.id())) {
116+
ctx.result("Your Minecraft account is already linked to your Mod Garden account.");
117+
ctx.status(200);
118+
return;
119+
}
120+
ctx.result("The specified Minecraft account has already been linked to a Mod Garden account.");
121+
ctx.status(400);
139122
return;
140123
}
141124

142-
accountCheckStatement.setString(1, dataResult.getOrThrow().toString());
143-
accountCheckStatement.setString(2, discordId);
125+
insertStatement.setString(1, uuid);
126+
insertStatement.setString(2, user.id());
144127
insertStatement.execute();
145128

146-
ctx.result("Successfully linked " + capitalisedService + " account to Mod Garden account associated with Discord ID '" + discordId + "'.");
129+
ctx.result("Successfully linked Minecraft account to Mod Garden account associated with Discord ID '" + discordId + "'.");
147130
ctx.status(201);
148131
}
149132
}

0 commit comments

Comments
 (0)