1
0
mirror of https://github.com/golang/go synced 2024-11-18 15:14:44 -07:00

godoc/dl: use datastore to retrieve secret key.

godoc still runs on App Engine (not Managed VMs). The metadata server is only
available from Compute Engine and Managed VMs, but not App Engine.

Change-Id: I0e5e9ef3f169f6d24ca7562df744c8f1556b825f
Reviewed-on: https://go-review.googlesource.com/17391
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Chris Broadfoot 2015-12-03 12:01:13 -08:00
parent b844739462
commit eb69368e05

View File

@ -21,6 +21,7 @@ import (
"sort"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/net/context"
@ -30,7 +31,6 @@ import (
"google.golang.org/appengine/log"
"google.golang.org/appengine/memcache"
"google.golang.org/appengine/user"
"google.golang.org/cloud/compute/metadata"
)
const (
@ -39,12 +39,6 @@ const (
cacheDuration = time.Hour
)
var builderKey string
func init() {
builderKey, _ = metadata.ProjectAttributeValue("builder-key")
}
func RegisterHandlers(mux *http.ServeMux) {
mux.Handle("/dl", http.RedirectHandler("/dl/", http.StatusFound))
mux.HandleFunc("/dl/", getHandler) // also serves listHandler
@ -336,10 +330,6 @@ func uploadHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "bad user", http.StatusForbidden)
return
}
if builderKey == "" {
http.Error(w, "no builder-key found in project metadata", http.StatusInternalServerError)
return
}
if r.FormValue("key") != userKey(c, user) {
http.Error(w, "bad key", http.StatusForbidden)
return
@ -393,7 +383,7 @@ func validUser(user string) bool {
}
func userKey(c context.Context, user string) string {
h := hmac.New(md5.New, []byte(builderKey))
h := hmac.New(md5.New, []byte(secret(c)))
h.Write([]byte("user-" + user))
return fmt.Sprintf("%x", h.Sum(nil))
}
@ -448,3 +438,55 @@ var prettyStrings = map[string]string{
"installer": "Installer",
"source": "Source",
}
// Code below copied from x/build/app/key
var theKey struct {
sync.RWMutex
builderKey
}
type builderKey struct {
Secret string
}
func (k *builderKey) Key(c context.Context) *datastore.Key {
return datastore.NewKey(c, "BuilderKey", "root", 0, nil)
}
func secret(c context.Context) string {
// check with rlock
theKey.RLock()
k := theKey.Secret
theKey.RUnlock()
if k != "" {
return k
}
// prepare to fill; check with lock and keep lock
theKey.Lock()
defer theKey.Unlock()
if theKey.Secret != "" {
return theKey.Secret
}
// fill
if err := datastore.Get(c, theKey.Key(c), &theKey.builderKey); err != nil {
if err == datastore.ErrNoSuchEntity {
// If the key is not stored in datastore, write it.
// This only happens at the beginning of a new deployment.
// The code is left here for SDK use and in case a fresh
// deployment is ever needed. "gophers rule" is not the
// real key.
if !appengine.IsDevAppServer() {
panic("lost key from datastore")
}
theKey.Secret = "gophers rule"
datastore.Put(c, theKey.Key(c), &theKey.builderKey)
return theKey.Secret
}
panic("cannot load builder key: " + err.Error())
}
return theKey.Secret
}