Skip to content

Commit a517a77

Browse files
committed
Add support for signing Static Maps API requests
1 parent e6f6ec2 commit a517a77

File tree

12 files changed

+79
-45
lines changed

12 files changed

+79
-45
lines changed

client.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ func WithAPIKey(apiKey string) ClientOption {
9393
}
9494
}
9595

96+
// WithAPIKeyAndSignature configures a Maps API client with an API Key and
97+
// signature. The signature is assumed to be URL modified Base64 encoded.
98+
func WithAPIKeyAndSignature(apiKey, signature string) ClientOption {
99+
return func(c *Client) error {
100+
c.apiKey = apiKey
101+
decoded, err := base64.URLEncoding.DecodeString(signature)
102+
if err != nil {
103+
return err
104+
}
105+
c.signature = decoded
106+
return nil
107+
}
108+
}
109+
96110
// WithBaseURL configures a Maps API client with a custom base url
97111
func WithBaseURL(baseURL string) ClientOption {
98112
return func(c *Client) error {
@@ -133,9 +147,10 @@ func WithRateLimit(requestsPerSecond int) ClientOption {
133147
}
134148

135149
type apiConfig struct {
136-
host string
137-
path string
138-
acceptsClientID bool
150+
host string
151+
path string
152+
acceptsClientID bool
153+
acceptsSignature bool
139154
}
140155

141156
type apiRequest interface {
@@ -162,7 +177,7 @@ func (c *Client) get(ctx context.Context, config *apiConfig, apiReq apiRequest)
162177
if err != nil {
163178
return nil, err
164179
}
165-
q, err := c.generateAuthQuery(config.path, apiReq.params(), config.acceptsClientID)
180+
q, err := c.generateAuthQuery(config.path, apiReq.params(), config.acceptsClientID, config.acceptsSignature)
166181
if err != nil {
167182
return nil, err
168183
}
@@ -189,7 +204,7 @@ func (c *Client) post(ctx context.Context, config *apiConfig, apiReq interface{}
189204
return nil, err
190205
}
191206
req.Header.Set("Content-Type", "application/json")
192-
q, err := c.generateAuthQuery(config.path, url.Values{}, config.acceptsClientID)
207+
q, err := c.generateAuthQuery(config.path, url.Values{}, config.acceptsClientID, config.acceptsSignature)
193208
if err != nil {
194209
return nil, err
195210
}
@@ -241,16 +256,20 @@ func (c *Client) getBinary(ctx context.Context, config *apiConfig, apiReq apiReq
241256
return binaryResponse{httpResp.StatusCode, httpResp.Header.Get("Content-Type"), httpResp.Body}, nil
242257
}
243258

244-
func (c *Client) generateAuthQuery(path string, q url.Values, acceptClientID bool) (string, error) {
259+
func (c *Client) generateAuthQuery(path string, q url.Values, acceptClientID bool, acceptsSignature bool) (string, error) {
245260
if c.channel != "" {
246261
q.Set("channel", c.channel)
247262
}
248263
if c.apiKey != "" {
249264
q.Set("key", c.apiKey)
265+
if acceptsSignature && len(c.signature) > 0 {
266+
return internal.SignURL(path, c.signature, q)
267+
}
250268
return q.Encode(), nil
251269
}
252270
if acceptClientID {
253-
return internal.SignURL(path, c.clientID, c.signature, q)
271+
q.Set("client", c.clientID)
272+
return internal.SignURL(path, c.signature, q)
254273
}
255274
return "", errors.New("maps: API Key missing")
256275
}

directions.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ import (
2525
)
2626

2727
var directionsAPI = &apiConfig{
28-
host: "https://maps.googleapis.com",
29-
path: "/maps/api/directions/json",
30-
acceptsClientID: true,
28+
host: "https://maps.googleapis.com",
29+
path: "/maps/api/directions/json",
30+
acceptsClientID: true,
31+
acceptsSignature: false,
3132
}
3233

3334
// Directions issues the Directions request and retrieves the Response

distancematrix.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ import (
2626
)
2727

2828
var distanceMatrixAPI = &apiConfig{
29-
host: "https://maps.googleapis.com",
30-
path: "/maps/api/distancematrix/json",
31-
acceptsClientID: true,
29+
host: "https://maps.googleapis.com",
30+
path: "/maps/api/distancematrix/json",
31+
acceptsClientID: true,
32+
acceptsSignature: false,
3233
}
3334

3435
// DistanceMatrix makes a Distance Matrix API request

elevation.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ import (
2525
)
2626

2727
var elevationAPI = &apiConfig{
28-
host: "https://maps.googleapis.com",
29-
path: "/maps/api/elevation/json",
30-
acceptsClientID: true,
28+
host: "https://maps.googleapis.com",
29+
path: "/maps/api/elevation/json",
30+
acceptsClientID: true,
31+
acceptsSignature: false,
3132
}
3233

3334
// Elevation makes an Elevation API request

examples/staticmap/cmdline/main.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
var (
3131
apiKey = flag.String("key", "", "API Key for using Google Maps API.")
3232
clientID = flag.String("client_id", "", "ClientID for Maps for Work API access.")
33-
signature = flag.String("signature", "", "Signature for Maps for Work API access.")
33+
signature = flag.String("signature", "", "Signature for Maps for Work API access or optional APIs.")
3434
center = flag.String("center", "", "Center the center of the map, equidistant from all edges of the map.")
3535
zoom = flag.Int("zoom", -1, "Zoom the zoom level of the map, which determines the magnification level of the map.")
3636
size = flag.String("size", "", "Size defines the rectangular dimensions of the map image.")
@@ -60,7 +60,11 @@ func main() {
6060
var client *maps.Client
6161
var err error
6262
if *apiKey != "" {
63-
client, err = maps.NewClient(maps.WithAPIKey(*apiKey))
63+
if *signature != "" {
64+
client, err = maps.NewClient(maps.WithAPIKeyAndSignature(*apiKey, *signature))
65+
} else {
66+
client, err = maps.NewClient(maps.WithAPIKey(*apiKey))
67+
}
6468
} else if *clientID != "" || *signature != "" {
6569
client, err = maps.NewClient(maps.WithClientIDAndSignature(*clientID, *signature))
6670
} else {

geocoding.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ import (
2525
)
2626

2727
var geocodingAPI = &apiConfig{
28-
host: "https://maps.googleapis.com",
29-
path: "/maps/api/geocode/json",
30-
acceptsClientID: true,
28+
host: "https://maps.googleapis.com",
29+
path: "/maps/api/geocode/json",
30+
acceptsClientID: true,
31+
acceptsSignature: false,
3132
}
3233

3334
// Geocode makes a Geocoding API request

geolocation.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ import (
2323
)
2424

2525
var geolocationAPI = &apiConfig{
26-
host: "https://www.googleapis.com",
27-
path: "/geolocation/v1/geolocate",
28-
acceptsClientID: true,
26+
host: "https://www.googleapis.com",
27+
path: "/geolocation/v1/geolocate",
28+
acceptsClientID: true,
29+
acceptsSignature: false,
2930
}
3031

3132
// Geolocate makes a Geolocation API request

internal/signer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ func generateSignature(key []byte, message string) (string, error) {
2929
return base64.URLEncoding.EncodeToString(mac.Sum(nil)), nil
3030
}
3131

32-
// SignURL signs a url with a clientID and signature.
32+
// SignURL signs a url with a signature.
3333
// The signature is assumed to be in URL safe base64 encoding.
3434
// The returned signature string is URLEncoded.
3535
// See: https://developers.google.com/maps/documentation/business/webservices/auth#digital_signatures
36-
func SignURL(path, clientID string, signature []byte, q url.Values) (string, error) {
37-
q.Set("client", clientID)
36+
// See: https://developers.google.com/maps/faq#using-google-maps-apis
37+
func SignURL(path string, signature []byte, q url.Values) (string, error) {
3838
encodedQuery := q.Encode()
3939
message := fmt.Sprintf("%s?%s", path, encodedQuery)
4040
s, err := generateSignature(signature, message)

places.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ import (
3131
)
3232

3333
var placesNearbySearchAPI = &apiConfig{
34-
host: "https://maps.googleapis.com",
35-
path: "/maps/api/place/nearbysearch/json",
36-
acceptsClientID: true,
34+
host: "https://maps.googleapis.com",
35+
path: "/maps/api/place/nearbysearch/json",
36+
acceptsClientID: true,
37+
acceptsSignature: false,
3738
}
3839

3940
// NearbySearch lets you search for places within a specified area. You can refine

roads.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,24 @@ import (
2525
)
2626

2727
var snapToRoadsAPI = &apiConfig{
28-
host: "https://roads.googleapis.com",
29-
path: "/v1/snapToRoads",
30-
acceptsClientID: false,
28+
host: "https://roads.googleapis.com",
29+
path: "/v1/snapToRoads",
30+
acceptsClientID: false,
31+
acceptsSignature: false,
3132
}
3233

3334
var nearestRoadsAPI = &apiConfig{
34-
host: "https://roads.googleapis.com",
35-
path: "/v1/nearestRoads",
36-
acceptsClientID: false,
35+
host: "https://roads.googleapis.com",
36+
path: "/v1/nearestRoads",
37+
acceptsClientID: false,
38+
acceptsSignature: false,
3739
}
3840

3941
var speedLimitsAPI = &apiConfig{
40-
host: "https://roads.googleapis.com",
41-
path: "/v1/speedLimits",
42-
acceptsClientID: false,
42+
host: "https://roads.googleapis.com",
43+
path: "/v1/speedLimits",
44+
acceptsClientID: false,
45+
acceptsSignature: false,
4346
}
4447

4548
// SnapToRoad makes a Snap to Road API request

0 commit comments

Comments
 (0)