dinheiro

commit 27b23b2d984e015fec161c26f40473b4f504e3f7

Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>

wip auth

 auth/middleware.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++
 cmd/server.go | 8 ++
 go.mod | 1 
 go.sum | 1 
 types/user.go | 2 


diff --git a/auth/middleware.go b/auth/middleware.go
new file mode 100644
index 0000000000000000000000000000000000000000..2fc687ab90e439a3786394bd3f7f728967993bee
--- /dev/null
+++ b/auth/middleware.go
@@ -0,0 +1,129 @@
+package auth
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"strings"
+	"time"
+
+	"golang.org/x/crypto/bcrypt"
+
+	"git.eletrotupi.com/git/dinheiro/db"
+	"git.eletrotupi.com/git/dinheiro/types"
+)
+
+var authCtxKey = &contextKey{"auth"}
+
+type contextKey struct {
+	name string
+}
+
+// This is the representation of our currentUser
+type AuthContext struct {
+	UserID		int
+	Email		string
+	CreatedAt	time.Time
+	UpdatedAt	time.Time
+}
+
+type AuthCookie struct {
+	UserID	int `json:"id"`
+}
+
+func authError(writer http.ResponseWriter, reason string, statusCode int) {
+	writer.WriteHeader(statusCode)
+	writer.Write([]byte(reason))
+}
+
+func LookupUserAndGenerateCtx(ctx context.Context, email string) (*AuthContext, error) {
+	var (
+		authCtx AuthContext
+		err error
+	)
+
+	dbConn := db.ForContext(ctx)
+	row := dbConn.QueryRow(`SELECT id, email, created_at, updated_at FROM users WHERE email = $1`, email)
+
+	if err = row.Scan(&authCtx.UserID, &authCtx.Email, &authCtx.CreatedAt, &authCtx.UpdatedAt); err != nil {
+		return nil, fmt.Errorf("Something went off when creating the auth context %s", err)
+	}
+
+	return &authCtx, nil
+}
+
+// This method authenticate the user, populate a AuthContext and set the cookie
+// on the request
+func authenticate(w http.ResponseWriter, r *http.Request, next http.Handler) {
+	var (
+		//authCookie AuthCookie
+		user types.User
+		err error
+	)
+
+	err = r.ParseForm()
+	if err != nil {
+		authError(w, "Couldn't parse form", http.StatusInternalServerError)
+	}
+
+	email := r.Form.Get("email")
+	password := r.Form.Get("password")
+
+	dbConn := db.ForContext(r.Context())
+	row := dbConn.QueryRow(
+		`SELECT id, email, encrypted_password FROM users WHERE email = $1`,
+		email)
+
+	if err = row.Scan(&user.ID, &user.Email, &user.EncryptedPassword); err != nil {
+		authError(w, "Email wasn't found", http.StatusUnauthorized)
+		return
+	}
+
+	err = bcrypt.CompareHashAndPassword([]byte(user.EncryptedPassword), []byte(password))
+	if err != nil {
+		authError(w, "Incorrect Password", http.StatusUnauthorized)
+		return
+	}
+
+	authCtx, err := LookupUserAndGenerateCtx(r.Context(), user.Email)
+	if err != nil {
+		authError(w, err.Error(), http.StatusForbidden)
+
+		return
+	}
+
+	// TODO: Write the cookie part here
+	//authCookie = ...
+
+	ctx := context.WithValue(r.Context(), authCtxKey, authCtx)
+	r = r.WithContext(ctx)
+	next.ServeHTTP(w, r)
+}
+
+// This authenticate from an existing cookie sent by the browser
+// It'll decrypt the cookie, unmarshal into a AuthCookie struct
+// Then populate the AuthContext (our current user)
+func authFromCookie(cookie *http.Cookie, w http.ResponseWriter, r *http.Request, next http.Handler) {
+}
+
+func Middleware() func(http.Handler) http.Handler {
+	return func(next http.Handler) http.Handler {
+		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			cookie, err := r.Cookie("dinheiro.v1")
+			if err == nil {
+				authFromCookie(cookie, w, r, next)
+
+				return
+			}
+
+			if strings.HasPrefix(r.URL.Path, "/auth") {
+				authenticate(w, r, next)
+
+				return
+			}
+
+			next.ServeHTTP(w, r)
+			return
+		})
+	}
+}




diff --git a/cmd/server.go b/cmd/server.go
index 82e95bff497f0a492f0959bcc470a48ab263df5f..297e9b11235a804fdbd81cb5789eef7f05357750 100644
--- a/cmd/server.go
+++ b/cmd/server.go
@@ -7,7 +7,6 @@ 	"path/filepath"
 	"strings"
 	"net/http"
 	"database/sql"
-	"encoding/json"
 
 	"github.com/go-chi/chi/v5"
 	"github.com/go-chi/chi/v5/middleware"
@@ -18,7 +17,7 @@ 	"git.eletrotupi.com/git/dinheiro/config"
 	"git.eletrotupi.com/git/dinheiro/db"
 	"git.eletrotupi.com/git/dinheiro/keys"
 	"git.eletrotupi.com/git/dinheiro/redis"
-	"git.eletrotupi.com/git/dinheiro/types"
+	"git.eletrotupi.com/git/dinheiro/auth"
 )
 
 func FileServer(router chi.Router, path string, root http.FileSystem) {
@@ -64,6 +63,10 @@ 		}
 
 		w.Write(fileData)
 	})
+
+	router.Post("/auth", func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("authenticated!"))
+	})
 }
 
 func Server() {
@@ -96,6 +99,7 @@
 	rc := goRedis.NewClient(ropts)
 	router.Use(config.Middleware(appConfig))
 	router.Use(db.Middleware(dbConn))
+	router.Use(auth.Middleware())
 	router.Use(redis.Middleware(rc))
 	router.Use(middleware.RealIP)
 	router.Use(middleware.Logger)




diff --git a/go.mod b/go.mod
index c035ff8fb6192a29add238c08eb04b9cc6030af4..c3d720e4dc20ab7c24acbe89f256f0c48ce6508e 100644
--- a/go.mod
+++ b/go.mod
@@ -9,4 +9,5 @@ 	github.com/go-chi/chi/v5 v5.0.3
 	github.com/go-redis/redis/v8 v8.9.0 // indirect
 	github.com/lib/pq v1.10.2 // indirect
 	github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec // indirect
+	golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
 )




diff --git a/go.sum b/go.sum
index 1845be0f720dd971af642d44c2f261d8fe593839..88929f2f47d685e7f1567bfd7ade279f15af9388 100644
--- a/go.sum
+++ b/go.sum
@@ -55,6 +55,7 @@ go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw=
 go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=




diff --git a/types/user.go b/types/user.go
index d0875c4528ba4e4ca9bbd1d19c529169072971d1..5356baebebdb7e4a0fdd64742d1e156502d14a20 100644
--- a/types/user.go
+++ b/types/user.go
@@ -9,6 +9,8 @@ 	ID int
 	FirstName string
 	LastName string
 	Username string
+	Email string
 	CreatedAt time.Time
 	UpdatedAt time.Time
+	EncryptedPassword string
 }