Skip to content

Commit f0ee151

Browse files
tcheericclaude
andcommitted
fix: address Qodana and SpotBugs static analysis issues
Code quality fixes: - Make RelayConnection and RelayPool final (CT_CONSTRUCTOR_THROW) - Make AdminConnectionListener static inner class - Fix similar log messages in RelayPool, alerting classes - Fix MismatchedCollectionQueryUpdate in WebhookAlertDelivery, RelayPool - Add @serial annotations to exception classes (MissingSerialAnnotation) - Remove dead local store in RelayHealthMonitor (DLS_DEAD_LOCAL_STORE) - Fix SQL injection pattern warning in BottinE2ETest - Fix duplicated JSON serialization in Nip05Record - Remove unused imports and code across modules Dependency updates for CVE fixes: - Spring Boot 3.2.4 -> 3.5.9 - JUnit 5.10.2 -> 5.12.2 - Logback 1.5.3 -> 1.5.15 - Micrometer 1.12.4 -> 1.14.3 - maven-pmd-plugin 3.21.2 -> 3.26.0 (Java 21 support) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 808a103 commit f0ee151

79 files changed

Lines changed: 518 additions & 162 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

nsecbunker-account/src/main/java/xyz/tcheeric/nsecbunker/account/nip05/Nip05Record.java

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.fasterxml.jackson.databind.ObjectMapper;
77
import lombok.Builder;
88
import lombok.Value;
9+
import lombok.extern.slf4j.Slf4j;
910
import xyz.tcheeric.nsecbunker.core.model.BunkerKey;
1011

1112
import java.util.List;
@@ -31,6 +32,7 @@
3132
*/
3233
@Value
3334
@Builder(toBuilder = true)
35+
@Slf4j
3436
public class Nip05Record {
3537

3638
private static final ObjectMapper DEFAULT_MAPPER = new ObjectMapper();
@@ -64,6 +66,8 @@ public List<String> getRelays() {
6466
try {
6567
return DEFAULT_MAPPER.readValue(relaysJson, STRING_LIST_TYPE);
6668
} catch (JsonProcessingException e) {
69+
log.debug("relays_json_parse_failed nip05={} relaysJson={} error={}",
70+
nip05, relaysJson, e.getMessage());
6771
return List.of();
6872
}
6973
}
@@ -144,19 +148,10 @@ public static Nip05Record fromBunkerKey(BunkerKey key, String username, String d
144148
Objects.requireNonNull(username, "username must not be null");
145149
Objects.requireNonNull(domain, "domain must not be null");
146150

147-
String relaysJsonStr = "[]";
148-
if (relays != null && !relays.isEmpty()) {
149-
try {
150-
relaysJsonStr = DEFAULT_MAPPER.writeValueAsString(relays);
151-
} catch (JsonProcessingException e) {
152-
relaysJsonStr = "[]";
153-
}
154-
}
155-
156151
return Nip05Record.builder()
157152
.nip05(username + "@" + domain)
158153
.pubkey(key.getPubkeyHex() != null ? key.getPubkeyHex() : key.getNpub())
159-
.relaysJson(relaysJsonStr)
154+
.relaysJson(serializeRelays(relays))
160155
.build();
161156
}
162157

@@ -186,19 +181,29 @@ public static Nip05Record of(String username, String domain, String pubkey) {
186181
* @return a new Nip05Record
187182
*/
188183
public static Nip05Record of(String username, String domain, String pubkey, List<String> relays) {
189-
String relaysJsonStr = "[]";
190-
if (relays != null && !relays.isEmpty()) {
191-
try {
192-
relaysJsonStr = DEFAULT_MAPPER.writeValueAsString(relays);
193-
} catch (JsonProcessingException e) {
194-
relaysJsonStr = "[]";
195-
}
196-
}
197-
198184
return Nip05Record.builder()
199185
.nip05(username + "@" + domain)
200186
.pubkey(pubkey)
201-
.relaysJson(relaysJsonStr)
187+
.relaysJson(serializeRelays(relays))
202188
.build();
203189
}
190+
191+
/**
192+
* Serializes a list of relay URLs to JSON string.
193+
*
194+
* <p>Returns empty array "[]" if relays is null, empty, or serialization fails.
195+
*
196+
* @param relays the relay URLs to serialize
197+
* @return JSON array string of relays
198+
*/
199+
private static String serializeRelays(List<String> relays) {
200+
if (relays == null || relays.isEmpty()) {
201+
return "[]";
202+
}
203+
try {
204+
return DEFAULT_MAPPER.writeValueAsString(relays);
205+
} catch (JsonProcessingException e) {
206+
return "[]";
207+
}
208+
}
204209
}

nsecbunker-account/src/main/java/xyz/tcheeric/nsecbunker/account/nip05/spi/DefaultNip05ManagerProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class DefaultNip05ManagerProvider implements Nip05ManagerProvider {
3030
* Creates a provider with default dependencies.
3131
*/
3232
public DefaultNip05ManagerProvider() {
33-
this(new DefaultAccountManager(), new ObjectMapper());
33+
this(null, null);
3434
}
3535

3636
/**
@@ -39,7 +39,7 @@ public DefaultNip05ManagerProvider() {
3939
* @param accountManager the account manager to use
4040
*/
4141
public DefaultNip05ManagerProvider(AccountManager accountManager) {
42-
this(accountManager, new ObjectMapper());
42+
this(accountManager, null);
4343
}
4444

4545
/**

nsecbunker-account/src/main/java/xyz/tcheeric/nsecbunker/account/registration/AccountManager.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,38 @@ default CompletableFuture<Optional<AccountRegistrationResult>> findAccount(Strin
6464
* <p>Default implementation returns empty. Persistent implementations
6565
* should override this method to provide username-based lookup.</p>
6666
*
67+
* <p><b>Note:</b> Usernames are not unique across domains. For example,
68+
* "alice@example.com" and "alice@another.com" are different accounts.
69+
* This method may return ambiguous results in multi-domain scenarios.
70+
* For unambiguous lookups, use {@link #findByUsernameAndDomain(String, String)}
71+
* or {@link #findAccount(String)} with the full NIP-05 identifier.</p>
72+
*
6773
* @param username username to search for
68-
* @return the account if found, empty otherwise
74+
* @return the first matching account if found, empty otherwise
6975
*/
7076
default CompletableFuture<Optional<AccountRegistrationResult>> findByUsername(String username) {
7177
return CompletableFuture.completedFuture(Optional.empty());
7278
}
7379

80+
/**
81+
* Finds an account by username and domain.
82+
*
83+
* <p>This method provides unambiguous lookup by requiring both the username
84+
* and domain components of a NIP-05 identifier.</p>
85+
*
86+
* <p>Default implementation delegates to {@link #findAccount(String)} using
87+
* the combined NIP-05 identifier. Persistent implementations may override
88+
* for optimized queries.</p>
89+
*
90+
* @param username username (e.g., "alice")
91+
* @param domain domain (e.g., "example.com")
92+
* @return the account if found, empty otherwise
93+
*/
94+
default CompletableFuture<Optional<AccountRegistrationResult>> findByUsernameAndDomain(
95+
String username, String domain) {
96+
return findAccount(username + "@" + domain);
97+
}
98+
7499
/**
75100
* Finds all accounts for a given domain.
76101
*

nsecbunker-admin/src/main/java/xyz/tcheeric/nsecbunker/admin/AdminAuthenticator.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import lombok.extern.slf4j.Slf4j;
44
import xyz.tcheeric.nsecbunker.protocol.nip46.Nip46Request;
5-
import xyz.tcheeric.nsecbunker.protocol.nip46.Nip46Response;
65

76
import java.util.List;
87
import java.util.concurrent.CompletableFuture;

nsecbunker-admin/src/main/java/xyz/tcheeric/nsecbunker/admin/NsecBunkerAdminClient.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,20 @@
33
import lombok.Getter;
44
import lombok.extern.slf4j.Slf4j;
55
import nostr.id.Identity;
6-
import xyz.tcheeric.nsecbunker.connection.ConnectionListener;
7-
import xyz.tcheeric.nsecbunker.connection.ConnectionState;
8-
import xyz.tcheeric.nsecbunker.connection.ExponentialBackoffStrategy;
9-
import xyz.tcheeric.nsecbunker.connection.RelayConnection;
10-
import xyz.tcheeric.nsecbunker.connection.RelayListener;
11-
import xyz.tcheeric.nsecbunker.connection.RelayPool;
126
import xyz.tcheeric.nsecbunker.admin.key.DefaultKeyManager;
137
import xyz.tcheeric.nsecbunker.admin.key.KeyManager;
14-
import xyz.tcheeric.nsecbunker.admin.policy.DefaultPolicyManager;
15-
import xyz.tcheeric.nsecbunker.admin.policy.PolicyManager;
168
import xyz.tcheeric.nsecbunker.admin.permission.DefaultPermissionManager;
179
import xyz.tcheeric.nsecbunker.admin.permission.PermissionManager;
10+
import xyz.tcheeric.nsecbunker.admin.policy.DefaultPolicyManager;
11+
import xyz.tcheeric.nsecbunker.admin.policy.PolicyManager;
1812
import xyz.tcheeric.nsecbunker.admin.token.DefaultTokenManager;
1913
import xyz.tcheeric.nsecbunker.admin.token.TokenManager;
14+
import xyz.tcheeric.nsecbunker.connection.ConnectionListener;
15+
import xyz.tcheeric.nsecbunker.connection.ConnectionState;
16+
import xyz.tcheeric.nsecbunker.connection.ExponentialBackoffStrategy;
17+
import xyz.tcheeric.nsecbunker.connection.RelayConnection;
18+
import xyz.tcheeric.nsecbunker.connection.RelayListener;
19+
import xyz.tcheeric.nsecbunker.connection.RelayPool;
2020
import xyz.tcheeric.nsecbunker.core.exception.BunkerConnectionException;
2121
import xyz.tcheeric.nsecbunker.protocol.crypto.Nip04Crypto;
2222
import xyz.tcheeric.nsecbunker.protocol.nip46.Nip46Decoder;
@@ -650,7 +650,7 @@ public void onNotice(RelayConnection relay, String message) {
650650
/**
651651
* Connection listener for handling connection state changes.
652652
*/
653-
private class AdminConnectionListener implements ConnectionListener {
653+
private static class AdminConnectionListener implements ConnectionListener {
654654
@Override
655655
public void onConnected(String relayUrl) {
656656
log.debug("Connected to relay: {}", relayUrl);

nsecbunker-admin/src/main/java/xyz/tcheeric/nsecbunker/admin/permission/PermissionManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package xyz.tcheeric.nsecbunker.admin.permission;
22

3-
import xyz.tcheeric.nsecbunker.core.model.KeyUser;
43
import xyz.tcheeric.nsecbunker.core.model.BunkerPolicy;
4+
import xyz.tcheeric.nsecbunker.core.model.KeyUser;
55

66
import java.util.List;
77
import java.util.concurrent.CompletableFuture;

nsecbunker-admin/src/test/java/xyz/tcheeric/nsecbunker/admin/AdminConfigTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package xyz.tcheeric.nsecbunker.admin;
22

3-
import org.junit.jupiter.api.Test;
43
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
55

66
import java.time.Duration;
77
import java.util.List;
88

9-
import static org.assertj.core.api.Assertions.*;
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1011

1112
/**
1213
* Tests for {@link AdminConfig}.

nsecbunker-admin/src/test/java/xyz/tcheeric/nsecbunker/admin/AdminExceptionTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package xyz.tcheeric.nsecbunker.admin;
22

3-
import org.junit.jupiter.api.Test;
43
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
55
import xyz.tcheeric.nsecbunker.protocol.nip46.Nip46Error;
66

7-
import static org.assertj.core.api.Assertions.*;
7+
import static org.assertj.core.api.Assertions.assertThat;
88

99
/**
1010
* Tests for {@link AdminException}.

nsecbunker-admin/src/test/java/xyz/tcheeric/nsecbunker/admin/NsecBunkerAdminClientTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package xyz.tcheeric.nsecbunker.admin;
22

3-
import org.junit.jupiter.api.Test;
3+
import nostr.base.PublicKey;
44
import org.junit.jupiter.api.DisplayName;
5+
import org.junit.jupiter.api.Test;
56
import xyz.tcheeric.nsecbunker.connection.ConnectionState;
67

7-
import nostr.base.PublicKey;
8-
98
import java.time.Duration;
109
import java.util.List;
1110

12-
import static org.assertj.core.api.Assertions.*;
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1313

1414
/**
1515
* Tests for {@link NsecBunkerAdminClient}.

nsecbunker-client/src/main/java/xyz/tcheeric/nsecbunker/client/signer/NsecBunkerSigner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
import java.util.List;
1616
import java.util.Objects;
1717
import java.util.concurrent.CompletableFuture;
18-
import java.util.concurrent.atomic.AtomicReference;
1918
import java.util.concurrent.atomic.AtomicBoolean;
19+
import java.util.concurrent.atomic.AtomicReference;
2020
import java.util.function.Function;
2121

2222
/**

0 commit comments

Comments
 (0)