-
Notifications
You must be signed in to change notification settings - Fork 1
/
gmapsign.go
92 lines (80 loc) · 1.97 KB
/
gmapsign.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Package gmapsign provides helpers for signing requests to Google Maps APIs.
// The signature is included as the last query string var, as per Google's documentation.
package gmapsign
import (
"bufio"
"crypto/hmac"
"crypto/sha1" // nolint: gosec
"encoding/base64"
"fmt"
"io"
"net/url"
"strconv"
"strings"
)
// Pipeline signs incoming urls from the io.Reader and writes them in the io.Writer.
func Pipeline(in io.Reader, out io.Writer, signKey []byte) error {
scanner := bufio.NewScanner(in)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" {
continue
}
signed, err := Sign(line, signKey)
if err != nil {
return err
}
_, err = io.WriteString(out, signed+"\n")
if err != nil {
return err
}
}
return scanner.Err()
}
// Sign signs a string based URL.
func Sign(raw string, key []byte) (string, error) {
u, err := parseURL(raw)
if err != nil {
return "", fmt.Errorf("parsing: %w", err)
}
if err := SignURL(u, key); err != nil {
return "", fmt.Errorf("signing: %w", err)
}
return u.String(), nil
}
func parseURL(in string) (*url.URL, error) {
// replace literal unicode e.g. \u0026 -> &
in, err := strconv.Unquote("\"" + in + "\"")
if err != nil {
return nil, err
}
u, err := url.Parse(in)
if err != nil {
return nil, err
}
return u, nil
}
// SignURL signs a *url.URL.
func SignURL(u *url.URL, key []byte) error {
q := u.Query()
q.Del("signature")
encodedQuery := q.Encode()
s, err := sig(fmt.Sprintf("%s?%s", u.Path, encodedQuery), key)
if err != nil {
return err
}
u.RawQuery = fmt.Sprintf("%s&signature=%s", encodedQuery, s)
return nil
}
func sig(msg string, key []byte) (string, error) {
mac := hmac.New(sha1.New, key)
_, err := mac.Write([]byte(msg))
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(mac.Sum(nil)), nil
}
// DecodeSigningKey base64 decodes a signing key.
func DecodeSigningKey(raw string) ([]byte, error) {
return base64.URLEncoding.DecodeString(raw)
}