Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -30,7 +30,12 @@ public class UserConverter {
if (baseUser == null) {
return null;
}
return baseUser.toUser(uuid, key);
try {
return baseUser.toUser(uuid, key);
} catch (IllegalStateException e) {
// Plugin not found or other state issues - return null gracefully
return null;
}
Comment on lines +33 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Returning null from readUser when a plugin is not found is a great way to handle graceful degradation. However, please note that Base.getAllUsers() (line 304 in Base.java) directly adds the result of readUser(rs) to a list of type List<@NotNull User> without checking for null:

while (rs.next()) {
    users.add(readUser(rs));
}

This will result in null elements being added to a list that is contractually specified to contain only non-null Users, which can lead to unexpected NullPointerExceptions downstream when iterating over the list.

Recommendation:
Please update Base.getAllUsers() to filter out null users before adding them to the list:

User user = readUser(rs);
if (user != null) {
    users.add(user);
}

}

public static byte @NotNull [] toJson(@NotNull User user) {
Expand Down
44 changes: 37 additions & 7 deletions paper/src/main/java/net/sabafly/mailBox/database/impl/Base.java
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,19 @@ INSERT INTO mailbox_users (uuid, user_data, address) VALUES (?, ?, ?)
UUID id = UUID.fromString(rs.getString("id"));
UUID senderId = Optional.ofNullable(rs.getString("sender")).map(UUID::fromString).orElse(DummyMailUser.SYSTEM_UUID);
User sender = getUser(senderId);
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", "unknown", null);
}
Comment on lines +326 to +333

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using a hardcoded key value of "unknown" for all fallback DummyMailUsers will cause a database constraint violation.

Why this is an issue:

  1. The mailbox_users table has a UNIQUE constraint on the address column (which stores the user's key):
    CREATE TABLE IF NOT EXISTS mailbox_users (
        ...
        address TEXT DEFAULT NULL UNIQUE
    )
  2. When mail.sender() or mail.receiver() is called (e.g., when rendering mails in the GUI), it triggers database().getOrCreateUser(user).
  3. If the plugin is missing, getUser(uuid) returns null, so getOrCreateUser attempts to update/insert the fallback user into the database.
  4. If multiple fallback users are created with the same key "unknown", the database will attempt to set address = "mailbox:unknown" for multiple rows, violating the UNIQUE constraint and throwing a SQLException. This will crash the mail loading process entirely.

Solution:

Use the user's unique UUID string (e.g., senderId.toString() or receiverId.toString()) as the key value instead of "unknown". Since UUIDs are unique and valid key patterns (containing only lowercase letters, numbers, and hyphens), this completely avoids any database conflicts.

Suggested change
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", "unknown", null);
}
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", senderId.toString(), null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", receiverId.toString(), null);
}

String title = rs.getString("title");
String content = rs.getString("content");
boolean isRead = rs.getBoolean("is_read");
LocalDateTime sentTime = rs.getTimestamp("sentTime").toLocalDateTime();
Mail mail = new Mail(id, Objects.requireNonNull(sender), Objects.requireNonNull(receiver), title, content, List.of(), isRead, sentTime);
Mail mail = new Mail(id, sender, receiver, title, content, List.of(), isRead, sentTime);
mail.attachments(getMailAttachments(mail));
mails.add(mail);
}
Expand All @@ -344,13 +350,19 @@ INSERT INTO mailbox_users (uuid, user_data, address) VALUES (?, ?, ?)
UUID id = UUID.fromString(rs.getString("id"));
UUID senderId = Optional.ofNullable(rs.getString("sender")).map(UUID::fromString).orElse(DummyMailUser.SYSTEM_UUID);
User sender = getUser(senderId);
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", "unknown", null);
}
Comment on lines +353 to +360

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using a hardcoded key value of "unknown" for all fallback DummyMailUsers will cause a database constraint violation. Please use the unique UUID string as the key value instead.

Suggested change
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", "unknown", null);
}
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", senderId.toString(), null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", receiverId.toString(), null);
}

String title = rs.getString("title");
String content = rs.getString("content");
boolean isRead = rs.getBoolean("is_read");
LocalDateTime sentTime = rs.getTimestamp("sentTime").toLocalDateTime();
Mail mail = new Mail(id, Objects.requireNonNull(sender), Objects.requireNonNull(receiver), title, content, List.of(), isRead, sentTime);
Mail mail = new Mail(id, sender, receiver, title, content, List.of(), isRead, sentTime);
mail.attachments(getMailAttachments(mail));
mails.add(mail);
}
Expand Down Expand Up @@ -396,13 +408,19 @@ public int countMails(@NotNull User user, @NotNull TriState read) {
if (rs.next()) {
UUID senderId = Optional.ofNullable(rs.getString("sender")).map(UUID::fromString).orElse(DummyMailUser.SYSTEM_UUID);
User sender = getUser(senderId);
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", "unknown", null);
}
Comment on lines +411 to +418

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using a hardcoded key value of "unknown" for all fallback DummyMailUsers will cause a database constraint violation. Please use the unique UUID string as the key value instead.

Suggested change
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", "unknown", null);
}
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", senderId.toString(), null);
}
UUID receiverId = UUID.fromString(rs.getString("receiver"));
User receiver = getUser(receiverId);
if (receiver == null) {
receiver = DummyMailUser.createUser(receiverId, "Unknown Receiver", receiverId.toString(), null);
}

String title = rs.getString("title");
String content = rs.getString("content");
boolean read = rs.getBoolean("is_read");
LocalDateTime sentTime = rs.getTimestamp("sentTime").toLocalDateTime();
Mail mail = new Mail(id, Objects.requireNonNull(sender), Objects.requireNonNull(receiver), title, content, List.of(), read, sentTime);
Mail mail = new Mail(id, sender, receiver, title, content, List.of(), read, sentTime);
mail.attachments(getMailAttachments(mail));
return mail;
}
Expand Down Expand Up @@ -490,11 +508,14 @@ public void updateMailTemplate(@NotNull MailTemplate template) {
boolean autoSend = rs.getBoolean("auto_send");
UUID senderId = Optional.ofNullable(rs.getString("sender")).map(UUID::fromString).orElse(null);
User sender = getUser(senderId);
if (sender == null) {
sender = DummyMailUser.createUser(senderId != null ? senderId : DummyMailUser.SYSTEM_UUID, "Unknown Sender", "unknown", null);
}
Comment on lines +511 to +513

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using a hardcoded key value of "unknown" for all fallback DummyMailUsers will cause a database constraint violation. Please use the unique UUID string as the key value instead.

Suggested change
if (sender == null) {
sender = DummyMailUser.createUser(senderId != null ? senderId : DummyMailUser.SYSTEM_UUID, "Unknown Sender", "unknown", null);
}
if (sender == null) {
UUID fallbackId = senderId != null ? senderId : DummyMailUser.SYSTEM_UUID;
sender = DummyMailUser.createUser(fallbackId, "Unknown Sender", fallbackId.toString(), null);
}

Date startTime = rs.getTimestamp("start_time");
Date endTime = rs.getTimestamp("end_time");
Duration interval = Optional.of(rs.getLong("send_interval")).filter(l -> l > 0).map(Duration::ofSeconds).orElse(null);
String permission = rs.getString("permission");
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, Objects.requireNonNull(sender), LocalDateTime.ofInstant(startTime.toInstant(), ZoneId.systemDefault()), LocalDateTime.ofInstant(endTime.toInstant(), ZoneId.systemDefault()), interval, permission);
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, sender, LocalDateTime.ofInstant(startTime.toInstant(), ZoneId.systemDefault()), LocalDateTime.ofInstant(endTime.toInstant(), ZoneId.systemDefault()), interval, permission);
template.setAttachment(getTemplateAttachments(template));
return template;
}
Expand All @@ -520,11 +541,14 @@ public void updateMailTemplate(@NotNull MailTemplate template) {
boolean autoSend = rs.getBoolean("auto_send");
UUID senderId = Optional.ofNullable(rs.getString("sender")).map(UUID::fromString).orElse(null);
User sender = getUser(senderId);
if (sender == null) {
sender = DummyMailUser.createUser(senderId != null ? senderId : DummyMailUser.SYSTEM_UUID, "Unknown Sender", "unknown", null);
}
Comment on lines +544 to +546

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using a hardcoded key value of "unknown" for all fallback DummyMailUsers will cause a database constraint violation. Please use the unique UUID string as the key value instead.

Suggested change
if (sender == null) {
sender = DummyMailUser.createUser(senderId != null ? senderId : DummyMailUser.SYSTEM_UUID, "Unknown Sender", "unknown", null);
}
if (sender == null) {
UUID fallbackId = senderId != null ? senderId : DummyMailUser.SYSTEM_UUID;
sender = DummyMailUser.createUser(fallbackId, "Unknown Sender", fallbackId.toString(), null);
}

@Nullable LocalDateTime startTime = Optional.ofNullable(rs.getTimestamp("start_time")).map(timestamp -> LocalDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault())).orElse(null);
@Nullable LocalDateTime endTime = Optional.ofNullable(rs.getTimestamp("end_time")).map(timestamp -> LocalDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault())).orElse(null);
@Nullable Duration interval = Optional.of(rs.getLong("send_interval")).filter(l -> l > 0).map(Duration::ofSeconds).orElse(null);
@Nullable String permission = rs.getString("permission");
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, Objects.requireNonNull(sender), startTime, endTime, interval, permission);
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, sender, startTime, endTime, interval, permission);
template.setAttachment(getTemplateAttachments(template));
templates.add(template);
}
Expand All @@ -550,11 +574,14 @@ public void updateMailTemplate(@NotNull MailTemplate template) {
boolean autoSend = rs.getBoolean("auto_send");
UUID senderId = Optional.ofNullable(rs.getString("sender")).map(UUID::fromString).orElse(null);
User sender1 = getUser(senderId);
if (sender1 == null) {
sender1 = DummyMailUser.createUser(senderId != null ? senderId : DummyMailUser.SYSTEM_UUID, "Unknown Sender", "unknown", null);
}
Comment on lines +577 to +579

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using a hardcoded key value of "unknown" for all fallback DummyMailUsers will cause a database constraint violation. Please use the unique UUID string as the key value instead.

Suggested change
if (sender1 == null) {
sender1 = DummyMailUser.createUser(senderId != null ? senderId : DummyMailUser.SYSTEM_UUID, "Unknown Sender", "unknown", null);
}
if (sender1 == null) {
UUID fallbackId = senderId != null ? senderId : DummyMailUser.SYSTEM_UUID;
sender1 = DummyMailUser.createUser(fallbackId, "Unknown Sender", fallbackId.toString(), null);
}

@Nullable LocalDateTime startTime = Optional.ofNullable(rs.getTimestamp("start_time")).map(timestamp -> LocalDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault())).orElse(null);
@Nullable LocalDateTime endTime = Optional.ofNullable(rs.getTimestamp("end_time")).map(timestamp -> LocalDateTime.ofInstant(timestamp.toInstant(), ZoneId.systemDefault())).orElse(null);
@Nullable Duration interval = Optional.of(rs.getLong("send_interval")).filter(l -> l > 0).map(Duration::ofSeconds).orElse(null);
@Nullable String permission = rs.getString("permission");
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, Objects.requireNonNull(sender1), startTime, endTime, interval, permission);
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, sender1, startTime, endTime, interval, permission);
template.setAttachment(getTemplateAttachments(template));
templates.add(template);
}
Expand All @@ -580,11 +607,14 @@ public void updateMailTemplate(@NotNull MailTemplate template) {
boolean autoSend = rs.getBoolean("auto_send");
UUID senderId = Optional.ofNullable(rs.getString("sender")).map(UUID::fromString).orElse(DummyMailUser.SYSTEM_UUID);
User sender = getUser(senderId);
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
Comment on lines +610 to +612

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Using a hardcoded key value of "unknown" for all fallback DummyMailUsers will cause a database constraint violation. Please use the unique UUID string as the key value instead.

Suggested change
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", "unknown", null);
}
if (sender == null) {
sender = DummyMailUser.createUser(senderId, "Unknown Sender", senderId.toString(), null);
}

@Nullable LocalDateTime startTime = rs.getTimestamp("start_time") == null ? null : LocalDateTime.ofInstant(rs.getTimestamp("start_time").toInstant(), ZoneId.systemDefault());
@Nullable LocalDateTime endTime = rs.getTimestamp("end_time") == null ? null : LocalDateTime.ofInstant(rs.getTimestamp("end_time").toInstant(), ZoneId.systemDefault());
@Nullable Duration interval = Optional.of(rs.getLong("send_interval")).filter(l -> l > 0).map(Duration::ofSeconds).orElse(null);
@Nullable String permission = rs.getString("permission");
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, Objects.requireNonNull(sender), startTime, endTime, interval, permission);
MailTemplate template = new MailTemplate(id, title, content, List.of(), autoSend, sender, startTime, endTime, interval, permission);
template.setAttachment(getTemplateAttachments(template));
templates.add(template);
}
Expand Down