go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/impl/memory/user.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package memory 16 17 import ( 18 "context" 19 "crypto/sha256" 20 "encoding/binary" 21 "fmt" 22 "net/mail" 23 "net/url" 24 "strings" 25 "sync" 26 27 "go.chromium.org/luci/gae/service/user" 28 ) 29 30 type userData struct { 31 sync.RWMutex 32 user *user.User 33 } 34 35 // userImpl is a contextual pointer to the current userData. 36 type userImpl struct { 37 data *userData 38 } 39 40 var _ user.RawInterface = (*userImpl)(nil) 41 42 // useUser adds a user.RawInterface implementation to context, accessible 43 // by user.Raw(c) or the exported user methods. 44 func useUser(c context.Context) context.Context { 45 data := &userData{} 46 47 return user.SetFactory(c, func(ic context.Context) user.RawInterface { 48 return &userImpl{data} 49 }) 50 } 51 52 func (u *userImpl) Current() *user.User { 53 u.data.RLock() 54 defer u.data.RUnlock() 55 if u.data.user != nil && u.data.user.ClientID == "" { 56 ret := *u.data.user 57 return &ret 58 } 59 return nil 60 } 61 62 func (u *userImpl) CurrentOAuth(scopes ...string) (*user.User, error) { 63 // TODO(riannucci): something more clever in the Testable interface here? 64 u.data.RLock() 65 defer u.data.RUnlock() 66 if u.data.user != nil && u.data.user.ClientID != "" { 67 ret := *u.data.user 68 return &ret, nil 69 } 70 return nil, nil 71 } 72 73 func (u *userImpl) IsAdmin() bool { 74 u.data.RLock() 75 defer u.data.RUnlock() 76 return u.data.user != nil && u.data.user.Admin 77 } 78 79 func (u *userImpl) LoginURL(dest string) (string, error) { 80 return "https://fakeapp.example.com/_ah/login?redirect=" + url.QueryEscape(dest), nil 81 } 82 83 func (u *userImpl) LogoutURL(dest string) (string, error) { 84 return "https://fakeapp.example.com/_ah/logout?redirect=" + url.QueryEscape(dest), nil 85 } 86 87 func (u *userImpl) LoginURLFederated(dest, identity string) (string, error) { 88 return "", fmt.Errorf("LoginURLFederated is deprecated") 89 } 90 91 func (u *userImpl) OAuthConsumerKey() (string, error) { 92 return "", fmt.Errorf("OAuthConsumerKey is deprecated") 93 } 94 95 func (u *userImpl) GetTestable() user.Testable { return u } 96 97 func (u *userImpl) SetUser(user *user.User) { 98 u.data.Lock() 99 defer u.data.Unlock() 100 u.data.user = user 101 } 102 103 func (u *userImpl) Login(email, clientID string, admin bool) { 104 adr, err := mail.ParseAddress(email) 105 if err != nil { 106 panic(err) 107 } 108 email = adr.Address 109 110 parts := strings.Split(email, "@") 111 if len(parts) != 2 { 112 panic(fmt.Errorf("%q doesn't seem to be a valid email", email)) 113 } 114 115 id := sha256.Sum256([]byte("ID:" + email)) 116 117 u.SetUser(&user.User{ 118 Email: email, 119 AuthDomain: parts[1], 120 Admin: admin, 121 122 ID: fmt.Sprint(binary.LittleEndian.Uint64(id[:])), 123 ClientID: clientID, 124 }) 125 } 126 127 func (u *userImpl) Logout() { 128 u.SetUser(nil) 129 }