Created
June 5, 2015 13:39
-
-
Save rjeczalik/1ba387684de3f7d2bcc9 to your computer and use it in GitHub Desktop.
Panda Gate - signing proxy for Panda API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// +build ignore | |
package main | |
import ( | |
"crypto/hmac" | |
"crypto/sha256" | |
"encoding/base64" | |
"flag" | |
"fmt" | |
"log" | |
"net" | |
"net/http" | |
"net/http/httputil" | |
"net/url" | |
"os" | |
"strings" | |
"time" | |
) | |
var ( | |
addr = flag.String("http", ":8080", "") | |
cloud_id = flag.String("cloud_id", "", "") | |
accessKey = flag.String("access_key", "", "") | |
secretKey = flag.String("secret_key", "", "") | |
apiURL = flag.String("api_url", "https://api-gce.pandastream.com", "") | |
) | |
var queryFixer = strings.NewReplacer("+", "%20", "%5B", "[", "%5D", "]", "%7E", "~") | |
type SigningProxy struct { | |
*httputil.ReverseProxy | |
} | |
func NewSigningProxy(u *url.URL) SigningProxy { | |
return SigningProxy{ | |
ReverseProxy: httputil.NewSingleHostReverseProxy(u), | |
} | |
} | |
func (proxy SigningProxy) ServeHTTP(w http.ResponseWriter, req *http.Request) { | |
sign(req) | |
log.Println("signed:", req.URL) | |
proxy.ReverseProxy.ServeHTTP(w, req) | |
} | |
func sign(req *http.Request) { | |
query := req.URL.Query() | |
query.Set("cloud_id", *cloud_id) | |
query.Set("access_key", *accessKey) | |
query.Set("timestamp", time.Now().UTC().Format(time.RFC3339Nano)) | |
host := req.URL.Host | |
if h, _, err := net.SplitHostPort(host); err == nil { | |
host = h | |
} | |
mac := hmac.New(sha256.New, []byte(*secretKey)) | |
fmt.Fprintln(mac, req.Method) | |
fmt.Fprintln(mac, host) | |
fmt.Fprintln(mac, req.URL.Path) | |
fmt.Fprintln(mac, queryFixer.Replace(query.Encode())) | |
sign := base64.StdEncoding.EncodeToString(mac.Sum(nil)) | |
query.Set("signature", sign) | |
req.URL.RawQuery = query.Encode() | |
} | |
func die(v interface{}) { | |
fmt.Fprintln(os.Stderr, v) | |
os.Exit(1) | |
} | |
func run() error { | |
l, err := net.Listen("tcp", *addr) | |
if err != nil { | |
return err | |
} | |
log.Printf("pandagate: starting signing proxy on %s. . .", l.Addr()) | |
u, err := url.Parse(*apiURL) | |
if err != nil { | |
return err | |
} | |
return http.Serve(l, NewSigningProxy(u)) | |
} | |
func main() { | |
if err := run(); err != nil { | |
die(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment