// Authenticate checks a request's basic authentication, and associates a *models.User with the context // if so. Otherwise it handles responding to and closing the request. // // contextWithUser, authWasSuccessful := routes.Authenticate(ctx, w, r, logger, db) // // Use for any requests which expect to act on behalf of a user (which is most) func Authenticate(ctx context.Context, w http.ResponseWriter, r *http.Request, l services.Logger, db services.DB) (context.Context, bool) { l = l.WithPrefix("routes.Authenticate: ") var ( c *models.Credential u *models.User err error ) public, private, ok := r.BasicAuth() if !ok { l.Printf("authentication reverting from basic auth to session") // assume std lib didn't make a mistake, and the BasicAuth simply wasn't given // fall back to cookie if sesh, err := session(r, db); err != nil { switch err { case http.ErrNoCookie: l.Printf("no session cookie") case data.ErrNotFound: l.Printf("session token not found") default: l.Printf("session(r, db) error: %s", err) } l.Printf("authentication reverting from cookie to form values") public, private = r.FormValue(publicParam), r.FormValue(privateParam) } else if sesh.Valid() { if u, err := sesh.Owner(db); err != nil { l.Printf("sesh.Owner(db) error: %s", err) public, private = r.FormValue(publicParam), r.FormValue(privateParam) } else { return user.NewContext(ctx, u), true } } else { l.Printf("session no longer valid") public, private = r.FormValue(publicParam), r.FormValue(privateParam) } } if c, err = access.Authenticate(db, public, private); err != nil { l.Printf("authentication of (%s, %s) failed: couldn't find credential: %s", public, private, err) goto unauthorized // this error is on us, but it manifests as a failure to authenticate } if u, err = c.Owner(db); err != nil { l.Printf("authentication failed: couldn't load user's owner: %s", err) goto unauthorized // this error is also on us, but also manifests as a failure to authenticate } // successful authentications return user.NewContext(ctx, u), true // rejection unauthorized: http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return nil, false }
// basic logging func logRequest(handle http.HandlerFunc, logger services.Logger) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { logger.Printf("%s %s", r.Method, r.URL) handle(w, r) } }
func MobileLocationPOST(ctx context.Context, w http.ResponseWriter, r *http.Request, l services.Logger, db data.DB) { // Parse the form value if err := r.ParseForm(); err != nil { l.Printf("MobileLocationPOST Error: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } // Altitude alt := r.FormValue(altitudeParam) if alt == "" { http.Error(w, "You must specify an altitude", http.StatusBadRequest) return } altitude, err := strconv.ParseFloat(alt, 64) if err != nil { http.Error(w, "Parsing altitude", http.StatusBadRequest) return } // Latitude lat := r.FormValue(latitudeParam) if lat == "" { http.Error(w, "You must specify a latitude", http.StatusBadRequest) return } latitude, err := strconv.ParseFloat(lat, 64) if err != nil { http.Error(w, "Parsing latitude", http.StatusBadRequest) return } // Longitude lon := r.FormValue(longitudeParam) if lon == "" { http.Error(w, "You must specify an longitude", http.StatusBadRequest) return } longitude, err := strconv.ParseFloat(lon, 64) if err != nil { http.Error(w, "Parsing longitude", http.StatusBadRequest) return } // Retrieve the user this request was authenticated as u, ok := user.FromContext(ctx) if !ok { // This is certainly an issue, and should _never_ happen l.Print("MobileLocationPOST Error: failed to retrieve user from context") http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } // Create location loc := location.NewCoords(altitude, latitude, longitude) loc.SetID(db.NewID()) loc.SetOwner(u) now := loc.CreatedAt e := models.NewEvent() e.CreatedAt = now e.SetID(db.NewID()) e.SetOwner(u) e.Name = "Location Update" e.SetLocation(loc) e.Time = now e.UpdatedAt = now locationTag, err1 := tag.ForName(db, u, tag.Location) updateTag, err2 := tag.ForName(db, u, tag.Update) mobileTag, err3 := tag.ForName(db, u, tag.Mobile) if err1 != nil || err2 != nil || err3 != nil { l.Printf("MobileLocationPOST Error: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } e.IncludeTag(locationTag) e.IncludeTag(updateTag) e.IncludeTag(mobileTag) if err = db.Save(loc); err != nil { l.Printf("MobileLocationPOST Error: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } if err = db.Save(e); err != nil { l.Printf("MobileLocationPOST Error: %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } bytes, err := json.MarshalIndent(e, "", " ") if err != nil { l.Printf("MobileLocationPOST Error: while marshalling json %s", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } w.WriteHeader(http.StatusCreated) w.Header().Set("Content-Type", "application/json") w.Write(bytes) }