// Validate key query parameter for POST requests only.
key := r.FormValue("key")
builder := r.FormValue("builder")
- if r.Method == "POST" && !validKey(key, builder) {
+ if r.Method == "POST" && !validKey(c, key, builder) {
err = os.NewError("invalid key: " + key)
}
logErr(w, r, os.NewError("must supply builder in query string"))
return
}
- fmt.Fprint(w, builderKey(builder))
+ c := appengine.NewContext(r)
+ fmt.Fprint(w, builderKey(c, builder))
}
func init() {
return hash != ""
}
-func validKey(key, builder string) bool {
+func validKey(c appengine.Context, key, builder string) bool {
if appengine.IsDevAppServer() {
return true
}
- if key == secretKey {
+ if key == secretKey(c) {
return true
}
- return key == builderKey(builder)
+ return key == builderKey(c, builder)
}
-func builderKey(builder string) string {
- h := hmac.NewMD5([]byte(secretKey))
+func builderKey(c appengine.Context, builder string) string {
+ h := hmac.NewMD5([]byte(secretKey(c)))
h.Write([]byte(builder))
return fmt.Sprintf("%x", h.Sum())
}
package build
-import "appengine"
+import (
+ "sync"
-// Delete this init function before deploying to production.
-func init() {
- if !appengine.IsDevAppServer() {
- panic("please read misc/dashboard/app/build/key.go")
- }
+ "appengine"
+ "appengine/datastore"
+)
+
+var theKey struct {
+ sync.RWMutex
+ BuilderKey
+}
+
+type BuilderKey struct {
+ Secret string
}
-const secretKey = "" // Important! Put a secret here before deploying!
+func (k *BuilderKey) Key(c appengine.Context) *datastore.Key {
+ return datastore.NewKey(c, "BuilderKey", "root", 0, nil)
+}
+
+func secretKey(c appengine.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.String())
+ }
+
+ return theKey.Secret
+}