Index: impl/memory/user.go |
diff --git a/impl/memory/user.go b/impl/memory/user.go |
new file mode 100644 |
index 0000000000000000000000000000000000000000..eb1ce4f15798b49c5c2e2b2b1b04b2fe0590ec78 |
--- /dev/null |
+++ b/impl/memory/user.go |
@@ -0,0 +1,120 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package memory |
+ |
+import ( |
+ "crypto/sha256" |
+ "encoding/binary" |
+ "encoding/hex" |
+ "fmt" |
+ "net/url" |
+ "strings" |
+ "sync" |
+ |
+ "golang.org/x/net/context" |
+ |
+ "github.com/luci/gae/service/user" |
+) |
+ |
+type userData struct { |
+ sync.RWMutex |
+ user *user.User |
+} |
+ |
+// userImpl is a contextual pointer to the current userData. |
+type userImpl struct { |
+ data *userData |
+} |
+ |
+var _ user.Interface = (*userImpl)(nil) |
+ |
+// useUser adds a user.Interface implementation to context, accessible |
+// by user.Get(c) |
+func useUser(c context.Context) context.Context { |
+ data := &userData{} |
+ |
+ return user.SetFactory(c, func(ic context.Context) user.Interface { |
+ return &userImpl{data} |
+ }) |
+} |
+ |
+func (u *userImpl) Current() *user.User { |
+ u.data.RLock() |
+ defer u.data.RUnlock() |
+ if u.data.user != nil && u.data.user.ClientID == "" { |
+ ret := *u.data.user |
+ return &ret |
+ } |
+ return nil |
+} |
+ |
+func (u *userImpl) CurrentOAuth(scopes ...string) (*user.User, error) { |
+ // TODO(riannucci): something more clever in the Testing interface here? |
+ u.data.RLock() |
+ defer u.data.RUnlock() |
+ if u.data.user != nil && u.data.user.ClientID != "" { |
+ ret := *u.data.user |
+ return &ret, nil |
+ } |
+ return nil, nil |
+} |
+ |
+func (u *userImpl) IsAdmin() bool { |
+ u.data.RLock() |
+ defer u.data.RUnlock() |
+ return u.data.user.Admin |
+} |
+ |
+func (u *userImpl) LoginURL(dest string) (string, error) { |
+ return "https://fakeapp.example.com/_ah/login?redirect=" + url.QueryEscape(dest), nil |
+} |
+ |
+func (u *userImpl) LogoutURL(dest string) (string, error) { |
+ return "https://fakeapp.example.com/_ah/logout?redirect=" + url.QueryEscape(dest), nil |
+} |
+ |
+func (u *userImpl) LoginURLFederated(dest, identity string) (string, error) { |
+ return "", fmt.Errorf("LoginURLFederated is deprecated") |
+} |
+ |
+func (u *userImpl) OAuthConsumerKey() (string, error) { |
+ return "", fmt.Errorf("OAuthConsumerKey is deprecated") |
+} |
+ |
+func (u *userImpl) Testing() user.Testing { |
+ return u |
+} |
+ |
+func (u *userImpl) SetUser(user *user.User) { |
+ u.data.Lock() |
+ defer u.data.Unlock() |
+ u.data.user = user |
+} |
+ |
+func (u *userImpl) Login(email string, admin bool) string { |
+ parts := strings.SplitN(email, "@", 2) |
+ if len(parts) != 2 { |
+ panic(fmt.Errorf("%q doesn't seem to be a valid email", email)) |
+ } |
+ |
+ id := sha256.Sum256([]byte("ID:" + email)) |
+ clientIDRaw := sha256.Sum256([]byte("ClientID:" + email)) |
+ clientID := hex.EncodeToString(clientIDRaw[:]) |
Vadim Sh.
2015/12/14 18:54:08
but now you can't mock non-OAuth case with Login()
|
+ |
+ u.SetUser(&user.User{ |
+ Email: email, |
+ AuthDomain: parts[1], |
+ Admin: admin, |
+ |
+ ID: fmt.Sprint(binary.LittleEndian.Uint64(id[:])), |
+ ClientID: clientID, |
+ }) |
+ |
+ return clientID |
+} |
+ |
+func (u *userImpl) Logout() { |
+ u.SetUser(nil) |
+} |