-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Detail Bug Report
Summary
- Context:
HttpAppleMapsGatewayis the HTTP adapter responsible for communicating with the Apple Maps Server API. - Bug: The
lookupPlaceandreverseGeocodemethods inHttpAppleMapsGatewayfail to URL-encode their parameters (placeIdandlanguage) before constructing the request URI. - Actual vs. expected: The current implementation appends raw strings directly to the URI, causing
java.lang.IllegalArgumentExceptionif they contain illegal characters (like spaces) or allowing parameter injection; it is expected that all user-provided strings used in URIs are properly URL-encoded. - Impact: The application will crash with an unhandled
IllegalArgumentExceptionwhen searching for places with certain IDs or using certain language tags, and it is vulnerable to query parameter injection.
Code with bug
// src/main/java/com/williamcallahan/applemaps/adapters/mapsserver/HttpAppleMapsGateway.java
@Override
public PlaceResults reverseGeocode(double latitude, double longitude, String language) {
StringBuilder query = new StringBuilder();
query.append(QUERY_PREFIX)
.append(PARAMETER_LOCATION)
.append("=")
.append(latitude)
.append(LOCATION_SEPARATOR)
.append(longitude);
String resolvedLanguage = Objects.requireNonNull(language, "language");
if (!resolvedLanguage.isBlank()) {
query.append(PARAMETER_SEPARATOR)
.append(PARAMETER_LANGUAGE)
.append("=")
.append(resolvedLanguage); // <-- BUG 🔴 resolvedLanguage is not URL-encoded
}
return invokeApi("reverseGeocode", buildUri(REVERSE_GEOCODE_PATH, query.toString()), PlaceResults.class);
}
@Override
public Place lookupPlace(String placeId, String language) {
Objects.requireNonNull(placeId, "placeId");
String resolvedLanguage = Objects.requireNonNull(language, "language");
String queryString = "";
if (!resolvedLanguage.isBlank()) {
queryString = QUERY_PREFIX + PARAMETER_LANGUAGE + "=" + resolvedLanguage; // <-- BUG 🔴 resolvedLanguage is not URL-encoded
}
// <-- BUG 🔴 placeId is not URL-encoded and used in path
return invokeApi("place", URI.create(API_SERVER + PLACE_PATH + "/" + placeId + queryString), Place.class);
}Failing test
import com.williamcallahan.applemaps.adapters.mapsserver.HttpAppleMapsGateway;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class HttpAppleMapsGatewayEncodingTest {
@Test
public void testLookupPlaceWithSpaceInId() {
HttpAppleMapsGateway gateway = new HttpAppleMapsGateway("token", Duration.ofSeconds(5));
// This throws IllegalArgumentException because the space is not encoded before calling URI.create
assertThrows(IllegalArgumentException.class, () -> {
gateway.lookupPlace("place id with space", "en-US");
});
}
@Test
public void testReverseGeocodeWithSpaceInLanguage() {
HttpAppleMapsGateway gateway = new HttpAppleMapsGateway("token", Duration.ofSeconds(5));
// This throws IllegalArgumentException because the space is not encoded before calling URI.create
assertThrows(IllegalArgumentException.class, () -> {
gateway.reverseGeocode(37.33182, -122.03118, "en US");
});
}
}Test output:
HttpAppleMapsGatewayEncodingTest > testLookupPlaceWithSpaceInId() PASSED
HttpAppleMapsGatewayEncodingTest > testReverseGeocodeWithSpaceInLanguage() PASSED
Recommended fix
Use URLEncoder.encode() for the language parameter in both methods, and for the placeId parameter in lookupPlace. Note that for placeId in the path, it should technically use path encoding (where space is %20), whereas URLEncoder uses query encoding (where space is +), so care should be taken to use the correct encoding scheme or a URI builder.
@Override
public Place lookupPlace(String placeId, String language) {
Objects.requireNonNull(placeId, "placeId");
String resolvedLanguage = Objects.requireNonNull(language, "language");
String encodedId = URLEncoder.encode(placeId, StandardCharsets.UTF_8).replace("+", "%20"); // <-- FIX 🟢 path-segment encoding
String queryString = "";
if (!resolvedLanguage.isBlank()) {
queryString = QUERY_PREFIX + PARAMETER_LANGUAGE + "=" + URLEncoder.encode(resolvedLanguage, StandardCharsets.UTF_8); // <-- FIX 🟢 encode query param
}
return invokeApi("place", URI.create(API_SERVER + PLACE_PATH + "/" + encodedId + queryString), Place.class);
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working