chipmunk/server.go
Derek McQuay c99445e261
user route added and coded
can now hit user route (get, post, delete). Coded in some checks to see
if user is admin and has privledge. Currently turned off to allow work
from curl
2017-02-04 23:24:38 -08:00

353 lines
9.1 KiB
Go

package chipmunk
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"log"
"math/rand"
"net/http"
"strconv"
"time"
"github.com/gorilla/sessions"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
var store *sessions.CookieStore
var (
oauthConf = &oauth2.Config{
ClientID: "",
ClientSecret: "",
RedirectURL: "http://127.0.0.1:8080/api/v0/oauth_cb/",
Scopes: []string{"https://www.googleapis.com/auth/userinfo.email"},
Endpoint: google.Endpoint,
}
oauthStateString = strconv.Itoa(rand.Int())
)
var Version string = "dev"
var start time.Time
var users []user
var categories []category
type failure struct {
Success bool `json:"success"`
Error string `json:"error"`
}
func NewFailure(msg string) *failure {
return &failure{
Success: false,
Error: msg,
}
}
type Server struct {
clientID string
clientSecret string
cookieSecret string
db *DB
}
func init() {
log.SetFlags(log.Ltime)
start = time.Now()
}
func NewServer(sm *http.ServeMux, clientId, clientSecret, cookieSecret, dbhost, dbname, static string) (*Server, error) {
db, err := NewDB(dbhost, dbname)
if err != nil {
return nil, err
}
db.db.SetMaxOpenConns(32)
server := &Server{
clientID: clientId,
clientSecret: clientSecret,
cookieSecret: cookieSecret,
db: db,
}
addRoutes(sm, server, static)
return server, nil
}
func (s *Server) fakeSetup(w http.ResponseWriter, r *http.Request) {
//u := userInfo{
// Email: "derekmcquay@gmail.com",
//}
//addUser(u)
}
//func (s *Server) tranx(w http.ResponseWriter, r *http.Request) {
// //TODO add back in oauth
// //w.Header().Set("Content-Type", "application/json")
// //session, err := store.Get(r, "creds")
// //if err != nil {
// // http.Error(w, err.Error(), http.StatusInternalServerError)
// // return
// //}
// //if loggedIn := session.Values["authenticated"]; loggedIn != true {
// // http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
// // return
// //}
// switch r.Method {
// default:
// b, _ := json.Marshal(NewFailure("Allowed method: POST and GET"))
// http.Error(w, string(b), http.StatusBadRequest)
// return
// case "GET":
// u, err := getUser("derekmcquay@gmail.com") //TODO will grab this from session
// if err != nil {
// b, _ := json.Marshal(NewFailure(err.Error()))
// http.Error(w, string(b), http.StatusInternalServerError)
// return
// }
// json.NewEncoder(w).Encode(users[u].txs)
// if err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
// return
// }
// case "POST":
// u, err := getUser("derekmcquay@gmail.com") //TODO will grab this from session
// if err != nil {
// b, _ := json.Marshal(NewFailure(err.Error()))
// http.Error(w, string(b), http.StatusInternalServerError)
// return
// }
//
// t := tranx{}
// err = json.NewDecoder(r.Body).Decode(&t)
// if err != nil {
// http.Error(w, err.Error(), http.StatusBadRequest)
// return
// }
// defer r.Body.Close()
//
// users[u].txs = append(users[u].txs,
// tranx{
// Cost: t.Cost,
// Store: t.Store,
// Info: t.Info,
// Month: t.Month,
// },
// )
// }
//}
//
//func (s *Server) costPerMonth(w http.ResponseWriter, r *http.Request) {
// //TODO add back in oauth
// //w.Header().Set("Content-Type", "application/json")
// //session, err := store.Get(r, "creds")
// //if err != nil {
// // http.Error(w, err.Error(), http.StatusInternalServerError)
// // return
// //}
// //if loggedIn := session.Values["authenticated"]; loggedIn != true {
// // http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
// // return
// //}
// switch r.Method {
// default:
// b, _ := json.Marshal(NewFailure("Allowed method: GET"))
// http.Error(w, string(b), http.StatusBadRequest)
// return
// case "GET":
// u, err := getUser("derekmcquay@gmail.com") //TODO will grab this from session
// if err != nil {
// b, _ := json.Marshal(NewFailure(err.Error()))
// http.Error(w, string(b), http.StatusInternalServerError)
// return
// }
// monthCost := make(map[time.Month]float32)
// for _, t := range users[u].txs {
// c, ok := monthCost[t.Month]
// if !ok {
// monthCost[t.Month] = t.Cost
// continue
// }
// monthCost[t.Month] = t.Cost + c
// }
// err = json.NewEncoder(w).Encode(monthCost)
// if err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
// return
// }
// }
//}
//
//func (s *Server) listUsers(w http.ResponseWriter, r *http.Request) {
// //TODO add back in oauth
// //w.Header().Set("Content-Type", "application/json")
// //session, err := store.Get(r, "creds")
// //if err != nil {
// // http.Error(w, err.Error(), http.StatusInternalServerError)
// // return
// //}
// //if loggedIn := session.Values["authenticated"]; loggedIn != true {
// // http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
// // return
// //}
// switch r.Method {
// default:
// b, _ := json.Marshal(NewFailure("Allowed method: GET"))
// http.Error(w, string(b), http.StatusBadRequest)
// return
// case "GET":
// err := json.NewEncoder(w).Encode(users)
// if err != nil {
// http.Error(w, err.Error(), http.StatusInternalServerError)
// return
// }
// }
//}
//
func (s *Server) login(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "creds")
if loggedIn := session.Values["authenticated"]; loggedIn == true {
http.Redirect(w, r, "/static/", http.StatusTemporaryRedirect)
return
}
oauthConf.ClientID = s.clientID
oauthConf.ClientSecret = s.clientSecret
url := oauthConf.AuthCodeURL(oauthStateString, oauth2.AccessTypeOnline)
http.Redirect(w, r, url, http.StatusTemporaryRedirect)
}
func (s *Server) oauthCallback(w http.ResponseWriter, r *http.Request) {
state := r.FormValue("state")
if state != oauthStateString {
log.Printf("invalid oauth state, expected '%s', got '%s'\n", oauthStateString, state)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
code := r.FormValue("code")
token, err := oauthConf.Exchange(oauth2.NoContext, code)
if err != nil {
log.Printf("oauthConf.Exchange() failed with '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
oauthClient := oauthConf.Client(oauth2.NoContext, token)
email, err := oauthClient.Get("https://www.googleapis.com/oauth2/v3/userinfo")
if err != nil {
log.Printf("failed with getting userinfo: '%s'\n", err)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
defer email.Body.Close()
data, _ := ioutil.ReadAll(email.Body)
u := userInfo{}
err = json.Unmarshal(data, &u)
if err != nil {
b, _ := json.Marshal(NewFailure(err.Error()))
http.Error(w, string(b), http.StatusInternalServerError)
return
}
if authorizedEmail(u.Email) {
session, err := store.Get(r, "creds")
if err != nil {
if !session.IsNew {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
session.Values["authenticated"] = true
session.Values["uname"] = u.Email
if err := session.Save(r, w); err != nil {
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}
// TODO add psql user here
//addUser(u)
http.Redirect(w, r, "/static/", http.StatusTemporaryRedirect)
return
}
b, _ := json.Marshal(NewFailure("Not a authorized user"))
http.Error(w, string(b), http.StatusForbidden)
return
}
func (s *Server) auth(w http.ResponseWriter, r *http.Request) {
output := struct {
Auth bool `json:"auth"`
}{
Auth: false,
}
w.Header().Set("Content-Type", "application/json")
session, err := store.Get(r, "creds")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if loggedIn := session.Values["authenticated"]; loggedIn == true {
output.Auth = true
json.NewEncoder(w).Encode(output)
return
}
b, _ := json.Marshal(output)
http.Error(w, string(b), http.StatusUnauthorized)
}
func (s *Server) logout(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "creds")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
delete(session.Values, "authenticated")
delete(session.Values, "uname")
session.Save(r, w)
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func (s *Server) serverInfo(w http.ResponseWriter, r *http.Request) {
output := struct {
Version string `json:"version"`
Start string `json:"start"`
Uptime string `json:"uptime"`
}{
Version: Version,
Start: start.Format("2006-01-02 15:04:05"),
Uptime: time.Since(start).String(),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(output)
}
func (s *Server) plist(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "creds")
if err != nil {
if session.IsNew {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if loggedIn := session.Values["authenticated"]; loggedIn != true {
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
data, err := Asset("static/list.html")
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
req := bytes.NewReader(data)
io.Copy(w, req)
}
func (s *Server) health(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
io.WriteString(w, `{"alive": true}`)
}