github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/route/prefetch.go (about) 1 package route 2 3 import ( 4 "net/http" 5 6 "github.com/evergreen-ci/evergreen/apiv3" 7 "github.com/evergreen-ci/evergreen/apiv3/servicecontext" 8 "github.com/evergreen-ci/evergreen/model" 9 "github.com/evergreen-ci/evergreen/model/user" 10 "github.com/gorilla/context" 11 "github.com/gorilla/mux" 12 "github.com/pkg/errors" 13 ) 14 15 type ( 16 // custom types used to attach specific values to request contexts, to prevent collisions. 17 requestUserKey int 18 requestContextKey int 19 ) 20 21 const ( 22 // Key values used to map user and project data to request context. 23 // These are private custom types to avoid key collisions. 24 RequestUser requestUserKey = 0 25 RequestContext requestContextKey = 0 26 ) 27 28 // PrefetchFunc is a function signature that defines types of functions which may 29 // be used to fetch data before the main request handler is called. They should 30 // fetch data using the ServiceeContext and set them on the request context. 31 type PrefetchFunc func(*http.Request, servicecontext.ServiceContext) error 32 33 // PrefetchUser gets the user information from a request, and uses it to 34 // get the associated user from the database and attaches it to the request context. 35 func PrefetchUser(r *http.Request, sc servicecontext.ServiceContext) error { 36 // Grab API auth details from header 37 var authDataAPIKey, authDataName string 38 39 if len(r.Header["Api-Key"]) > 0 { 40 authDataAPIKey = r.Header["Api-Key"][0] 41 } 42 if len(r.Header["Auth-Username"]) > 0 { 43 authDataName = r.Header["Auth-Username"][0] 44 } 45 if len(authDataName) == 0 && len(r.Header["Api-User"]) > 0 { 46 authDataName = r.Header["Api-User"][0] 47 } 48 49 if len(authDataAPIKey) > 0 { 50 apiUser, err := sc.FindUserById(authDataName) 51 if apiUser.(*user.DBUser) != nil && err == nil { 52 if apiUser.GetAPIKey() != authDataAPIKey { 53 return apiv3.APIError{ 54 StatusCode: http.StatusUnauthorized, 55 Message: "Invalid API key", 56 } 57 } 58 context.Set(r, RequestUser, apiUser) 59 } 60 } 61 return nil 62 } 63 64 // PrefetchProjectContext gets the information related to the project that the request contains 65 // and fetches the associated project context and attaches that to the request context. 66 func PrefetchProjectContext(r *http.Request, sc servicecontext.ServiceContext) error { 67 vars := mux.Vars(r) 68 taskId := vars["task_id"] 69 buildId := vars["build_id"] 70 versionId := vars["version_id"] 71 patchId := vars["patch_id"] 72 projectId := vars["project_id"] 73 ctx, err := sc.FetchContext(taskId, buildId, versionId, patchId, projectId) 74 if err != nil { 75 return err 76 } 77 78 if ctx.ProjectRef != nil && ctx.ProjectRef.Private && GetUser(r) == nil { 79 // Project is private and user is not authorized so return not found 80 return apiv3.APIError{ 81 StatusCode: http.StatusNotFound, 82 Message: "Project not found", 83 } 84 } 85 86 if ctx.Patch != nil && GetUser(r) == nil { 87 return apiv3.APIError{ 88 StatusCode: http.StatusNotFound, 89 Message: "Not found", 90 } 91 } 92 context.Set(r, RequestContext, &ctx) 93 return nil 94 } 95 96 // GetUser returns the user associated with a given http request. 97 func GetUser(r *http.Request) *user.DBUser { 98 if rv := context.Get(r, RequestUser); rv != nil { 99 return rv.(*user.DBUser) 100 } 101 return nil 102 } 103 104 // GetProjectContext returns the project context associated with a 105 // given request. 106 func GetProjectContext(r *http.Request) (*model.Context, error) { 107 if rv := context.Get(r, RequestContext); rv != nil { 108 return rv.(*model.Context), nil 109 } 110 return &model.Context{}, errors.New("No context loaded") 111 } 112 113 // MustHaveProjectContext returns the project context set on the 114 // http request context. It panics if none is set. 115 func MustHaveProjectContext(r *http.Request) *model.Context { 116 pc, err := GetProjectContext(r) 117 if err != nil { 118 panic(err) 119 } 120 return pc 121 } 122 123 // MustHaveUser returns the user associated with a given request or panics 124 // if none is present. 125 func MustHaveUser(r *http.Request) *user.DBUser { 126 u := GetUser(r) 127 if u == nil { 128 panic("no user attached to request") 129 } 130 return u 131 }