Skip to content

Instantly share code, notes, and snippets.

@rjeczalik
Created June 5, 2015 13:39
Show Gist options
  • Save rjeczalik/1ba387684de3f7d2bcc9 to your computer and use it in GitHub Desktop.
Save rjeczalik/1ba387684de3f7d2bcc9 to your computer and use it in GitHub Desktop.
Panda Gate - signing proxy for Panda API
// +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