Skip to content

Commit 25fed66

Browse files
committed
Apply CRAI suggestions
1 parent 7b5b655 commit 25fed66

File tree

5 files changed

+37
-44
lines changed

5 files changed

+37
-44
lines changed

api/src/main/java/bisq/api/rest_api/endpoints/RestApiBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected Response buildOkResponse(Object entity) {
4242
* @return The HTTP response.
4343
*/
4444
protected Response buildNoContentResponse( ) {
45-
return buildResponse(Response.Status.NO_CONTENT, "");
45+
return Response.status(Response.Status.NO_CONTENT).build();
4646
}
4747

4848
protected Response buildNotFoundResponse(String message) {

api/src/main/java/bisq/api/rest_api/endpoints/devices/DevicesRestApi.java

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@
4949
description = "API for registering and unregistering mobile devices for push notifications"
5050
)
5151
public class DevicesRestApi extends RestApiBase {
52-
53-
private static final int APNS_TOKEN_LENGTH = 64;
54-
private static final String ALPHANUMERIC_REGEX = "^[a-zA-Z0-9]+$";
52+
private static final String APNS_HEX_REGEX = "^[0-9a-fA-F]+$";
5553

5654
private final DeviceRegistrationService deviceRegistrationService;
5755

@@ -92,20 +90,16 @@ public Response registerDevice(RegisterDeviceRequest request) {
9290
deviceId, deviceDescriptor, deviceToken.length(), platform
9391
);
9492

95-
// Basic structural validation only; platform-specific rules belong in the service
96-
if (!deviceToken.matches(ALPHANUMERIC_REGEX)) {
93+
// Platform-specific token validation
94+
if (platform == MobileDevicePlatform.IOS && !deviceToken.matches(APNS_HEX_REGEX)) {
9795
return buildResponse(
9896
Response.Status.BAD_REQUEST,
99-
"deviceToken must contain only alphanumeric characters"
97+
"APNs device token must be a hex-encoded string"
10098
);
10199
}
102100

103-
if (platform == MobileDevicePlatform.IOS && deviceToken.length() != APNS_TOKEN_LENGTH) {
104-
log.warn("Unexpected APNs token length: {}", deviceToken.length());
105-
}
106-
107101
try {
108-
deviceRegistrationService.register(
102+
deviceRegistrationService.register(
109103
deviceId,
110104
deviceToken,
111105
publicKeyBase64,
@@ -157,10 +151,10 @@ public Response unregisterDevice(@PathParam("deviceId") String deviceId) {
157151

158152
private boolean isValid(RegisterDeviceRequest request) {
159153
return request != null
160-
&& !StringUtils.isEmpty(request.getDeviceId())
161-
&& !StringUtils.isEmpty(request.getDeviceToken())
162-
&& !StringUtils.isEmpty(request.getPublicKeyBase64())
163-
&& !StringUtils.isEmpty(request.getDeviceDescriptor())
154+
&& StringUtils.isNotEmpty(request.getDeviceId())
155+
&& StringUtils.isNotEmpty(request.getDeviceToken())
156+
&& StringUtils.isNotEmpty(request.getPublicKeyBase64())
157+
&& StringUtils.isNotEmpty(request.getDeviceDescriptor())
164158
&& request.getPlatform() != null;
165159
}
166160
}

bonded-roles/src/main/java/bisq/bonded_roles/mobile_notification_relay/MobileNotificationRelayClient.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,20 @@ public static Config from(com.typesafe.config.Config typesafeConfig) {
9393
}
9494

9595
private static TransportType getTransportTypeFromUrl(String url) {
96-
if (url.endsWith(".i2p")) {
97-
return TransportType.I2P;
98-
} else if (url.endsWith(".onion")) {
99-
return TransportType.TOR;
100-
} else {
101-
return TransportType.CLEAR;
96+
try {
97+
java.net.URI uri = java.net.URI.create(url);
98+
String host = uri.getHost();
99+
if (host != null) {
100+
if (host.endsWith(".i2p")) {
101+
return TransportType.I2P;
102+
} else if (host.endsWith(".onion")) {
103+
return TransportType.TOR;
104+
}
105+
}
106+
} catch (IllegalArgumentException e) {
107+
log.warn("Failed to parse URL for transport type detection: {}", url);
102108
}
109+
return TransportType.CLEAR;
103110
}
104111

105112
private final Set<Provider> providers;
@@ -214,7 +221,7 @@ private CompletableFuture<Boolean> sendToRelayServer(boolean isAndroid,
214221
String encryptedMessageHex,
215222
AtomicInteger recursionDepth) {
216223
if (noProviderAvailable) {
217-
return CompletableFuture.failedFuture(new RuntimeException("No block explorer provider available"));
224+
return CompletableFuture.failedFuture(new RuntimeException("No mobile notification relay provider available"));
218225
}
219226
if (shutdownStarted) {
220227
return CompletableFuture.failedFuture(new RuntimeException("Shutdown has already started"));
@@ -235,7 +242,7 @@ private CompletableFuture<Boolean> sendToRelayServer(boolean isAndroid,
235242
Pair<String, String> header = new Pair<>("User-Agent", userAgent);
236243
String result = client.get(param, Optional.of(header));
237244

238-
log.info("Received response from {}/{} after {} ms", client.getBaseUrl(), param, System.currentTimeMillis() - ts);
245+
log.info("Received response from {}/{} after {} ms", client.getBaseUrl(), ENDPOINT, System.currentTimeMillis() - ts);
239246
selectedProvider.set(selectNextProvider());
240247
shutdownHttpClient(client);
241248
return result.equals(SUCCESS);

notifications/src/main/java/bisq/notifications/mobile/registration/DeviceRegistrationService.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,29 +47,28 @@ public void register(String deviceId,
4747
String publicKeyBase64,
4848
String deviceDescriptor,
4949
MobileDevicePlatform platform) {
50-
checkArgument(StringUtils.isEmpty(deviceId), "deviceId must not be null or empty");
51-
checkArgument(StringUtils.isEmpty(deviceToken), "deviceToken must not be null or empty");
52-
checkArgument(StringUtils.isEmpty(publicKeyBase64), "publicKeyBase64 must not be null or empty");
53-
checkArgument(StringUtils.isEmpty(deviceDescriptor), "deviceDescriptor must not be null or empty");
50+
checkArgument(StringUtils.isNotEmpty(deviceId), "deviceId must not be null or empty");
51+
checkArgument(StringUtils.isNotEmpty(deviceToken), "deviceToken must not be null or empty");
52+
checkArgument(StringUtils.isNotEmpty(publicKeyBase64), "publicKeyBase64 must not be null or empty");
53+
checkArgument(StringUtils.isNotEmpty(deviceDescriptor), "deviceDescriptor must not be null or empty");
5454
checkNotNull(platform, "platform must not be null");
5555

56-
String tokenPreview = deviceToken.substring(0, Math.min(10, deviceToken.length())) + "...";
57-
String publicKeyPreview = publicKeyBase64.substring(0, Math.min(20, publicKeyBase64.length())) + "...";
58-
59-
log.info("Registering device - deviceId: {}, deviceDescriptor: {}, token: {}, publicKeyBase64: {}, platform: {}",
60-
deviceId, deviceDescriptor, tokenPreview, publicKeyPreview, platform);
56+
log.info("Registering device - deviceId: {}, deviceDescriptor: {}, platform: {}",
57+
deviceId, deviceDescriptor, platform);
6158

6259
MobileDeviceProfile mobileDeviceProfile = new MobileDeviceProfile(deviceId,
6360
deviceToken,
6461
publicKeyBase64,
6562
deviceDescriptor,
6663
platform);
67-
persistableStore.getDeviceByDeviceId().putIfAbsent(deviceId, mobileDeviceProfile);
68-
persist();
64+
MobileDeviceProfile previous = persistableStore.getDeviceByDeviceId().put(deviceId, mobileDeviceProfile);
65+
if (previous == null || !previous.equals(mobileDeviceProfile)) {
66+
persist();
67+
}
6968
}
7069

7170
public boolean unregister(String deviceId) {
72-
checkArgument(StringUtils.isEmpty(deviceId), "deviceId must not be null or empty");
71+
checkArgument(StringUtils.isNotEmpty(deviceId), "deviceId must not be null or empty");
7372

7473
MobileDeviceProfile previous = persistableStore.getDeviceByDeviceId().remove(deviceId);
7574
boolean hadValue = previous != null;

security/src/main/java/bisq/security/mobile_notifications/MobileNotificationEncryption.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public class MobileNotificationEncryption {
3636
/**
3737
* Encrypt the message using the device's public key (ECIES for EC keys).
3838
*
39-
* @param message The message to encrypt
4039
* @param publicKeyBase64 The Base64 encoded public key
40+
* @param message The message to encrypt
4141
* @return Base64 encoded encrypted message
4242
*/
4343
public static String encrypt(String publicKeyBase64, String message) throws GeneralSecurityException {
@@ -59,15 +59,8 @@ public static String encrypt(String publicKeyBase64, String message) throws Gene
5959
// Any mismatch in these parameters will cause decryption to fail silently or produce garbage.
6060
byte[] derivation = new byte[0]; // Intentionally empty, not null
6161
byte[] encoding = new byte[0]; // Intentionally empty, not null
62-
63-
// Size (in bits) of the symmetric encryption key derived via ECIES KDF.
64-
// 128 bits → AES-128-CBC is used internally by Bouncy Castle ECIES.
65-
// The MAC key (HMAC-SHA1) is derived alongside it.
66-
// NOTE: This value MUST match exactly on all platforms.
6762
int macKeySize = 128;
68-
6963
IESParameterSpec iesSpec = new IESParameterSpec(derivation, encoding, macKeySize);
70-
7164
Cipher cipher = Cipher.getInstance("ECIES", BouncyCastleProvider.PROVIDER_NAME);
7265
cipher.init(Cipher.ENCRYPT_MODE, publicKey, iesSpec);
7366
byte[] encryptedBytes = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));

0 commit comments

Comments
 (0)