package authboss import ( "context" "net/http" ) type contextKey string // CTX Keys for authboss const ( CTXKeyPID contextKey = "pid" CTXKeyUser contextKey = "user" CTXKeySessionState contextKey = "session" CTXKeyCookieState contextKey = "cookie" // CTXKeyData is a context key for the accumulating // map[string]interface{} (authboss.HTMLData) to pass to the // renderer CTXKeyData contextKey = "data" // CTXKeyValues is to pass the data submitted from API request or form // along in the context in case modules need it. The only module that needs // user information currently is remember so only auth/oauth2 are currently // going to use this. CTXKeyValues contextKey = "values" ) func (c contextKey) String() string { return "authboss ctx key " + string(c) } // CurrentUserID retrieves the current user from the session. func (a *Authboss) CurrentUserID(r *http.Request) (string, error) { if pid := r.Context().Value(CTXKeyPID); pid != nil { return pid.(string), nil } pid, _ := GetSession(r, SessionKey) return pid, nil } // CurrentUserIDP retrieves the current user but panics if it's not available for // any reason. func (a *Authboss) CurrentUserIDP(r *http.Request) string { i, err := a.CurrentUserID(r) if err != nil { panic(err) } else if len(i) == 0 { panic(ErrUserNotFound) } return i } // CurrentUser retrieves the current user from the session and the database. // Before the user is loaded from the database the context key is checked. // If the session doesn't have the user ID ErrUserNotFound will be returned. func (a *Authboss) CurrentUser(r *http.Request) (User, error) { if user := r.Context().Value(CTXKeyUser); user != nil { return user.(User), nil } pid, err := a.CurrentUserID(r) if err != nil { return nil, err } else if len(pid) == 0 { return nil, ErrUserNotFound } return a.currentUser(r.Context(), pid) } // CurrentUserP retrieves the current user but panics if it's not available for // any reason. func (a *Authboss) CurrentUserP(r *http.Request) User { i, err := a.CurrentUser(r) if err != nil { panic(err) } else if i == nil { panic(ErrUserNotFound) } return i } func (a *Authboss) currentUser(ctx context.Context, pid string) (User, error) { return a.Storage.Server.Load(ctx, pid) } // LoadCurrentUserID takes a pointer to a pointer to the request in order to // change the current method's request pointer itself to the new request that // contains the new context that has the pid in it. func (a *Authboss) LoadCurrentUserID(r **http.Request) (string, error) { pid, err := a.CurrentUserID(*r) if err != nil { return "", err } if len(pid) == 0 { return "", nil } ctx := context.WithValue((**r).Context(), CTXKeyPID, pid) *r = (**r).WithContext(ctx) return pid, nil } // LoadCurrentUserIDP loads the current user id and panics if it's not found func (a *Authboss) LoadCurrentUserIDP(r **http.Request) string { pid, err := a.LoadCurrentUserID(r) if err != nil { panic(err) } else if len(pid) == 0 { panic(ErrUserNotFound) } return pid } // LoadCurrentUser takes a pointer to a pointer to the request in order to // change the current method's request pointer itself to the new request that // contains the new context that has the user in it. Calls LoadCurrentUserID // so the primary id is also put in the context. func (a *Authboss) LoadCurrentUser(r **http.Request) (User, error) { if user := (*r).Context().Value(CTXKeyUser); user != nil { return user.(User), nil } pid, err := a.LoadCurrentUserID(r) if err != nil { return nil, err } if len(pid) == 0 { return nil, nil } ctx := (**r).Context() user, err := a.currentUser(ctx, pid) if err != nil { return nil, err } ctx = context.WithValue(ctx, CTXKeyUser, user) *r = (**r).WithContext(ctx) return user, nil } // LoadCurrentUserP does the same as LoadCurrentUser but panics if // the current user is not found. func (a *Authboss) LoadCurrentUserP(r **http.Request) User { user, err := a.LoadCurrentUser(r) if err != nil { panic(err) } else if user == nil { panic(ErrUserNotFound) } return user }