diff options
| author | Alexander Kavon <hawk@alexkavon.com> | 2023-11-29 02:05:38 -0500 |
|---|---|---|
| committer | Alexander Kavon <hawk@alexkavon.com> | 2023-11-29 02:05:38 -0500 |
| commit | 1c32e1497525bc6f609898f0f79bd6cc3e6d92fb (patch) | |
| tree | 99abc1c2690b151bfb3d45e9f76a8770b3597e7a /src/user | |
| parent | 5e26ebc96bd41f9d232573d873cb6cb55f0050c4 (diff) | |
user create/insert into users table, pgxpool defer moved to top of app, me.tmpl.html, secret hashing with argon2id, updated migrations
Diffstat (limited to 'src/user')
| -rw-r--r-- | src/user/routes.go | 56 | ||||
| -rw-r--r-- | src/user/user.go | 63 |
2 files changed, 107 insertions, 12 deletions
diff --git a/src/user/routes.go b/src/user/routes.go index f826822..64018d0 100644 --- a/src/user/routes.go +++ b/src/user/routes.go @@ -1,9 +1,10 @@ package user import ( - "fmt" + "log" "net/http" + "github.com/go-playground/validator/v10" "gitlab.com/alexkavon/newsstand/src/server" ) @@ -11,7 +12,7 @@ var Routes = server.Routes{ server.Route{ Name: "Create", Method: "GET", - Path: "/user/create", + Path: "/u/create", HandlerFunc: Create, }, server.Route{ @@ -23,19 +24,19 @@ var Routes = server.Routes{ server.Route{ Name: "LoginForm", Method: "GET", - Path: "/user/auth", + Path: "/u/auth", HandlerFunc: LoginForm, }, server.Route{ Name: "Authenticate", Method: "POST", - Path: "/user/auth", + Path: "/u/auth", HandlerFunc: Authenticate, }, server.Route{ Name: "Me", Method: "GET", - Path: "/user/me", + Path: "/u/me", AuthRequired: true, HandlerFunc: Show, }, @@ -50,8 +51,36 @@ func Create(s *server.Server) http.HandlerFunc { func Store(s *server.Server) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { r.ParseForm() - fmt.Println(r.PostForm) - s.Ui.RenderTemplate(w, "core", "messages", &struct{ Message string }{Message: "Congrats"}) + + user := &User{ + Db: s.Db, + Username: r.PostFormValue("username"), + Secret: r.PostFormValue("secret"), + Email: r.PostFormValue("email"), + } + // Validate User Input + v := validator.New() + err := v.Struct(user) + if err != nil { + log.Println("Validator failed", err.(validator.ValidationErrors)) + } + + // Hash secret + err = user.HashSecret() + if err != nil { + log.Println("Hash failure", err) + } + + // Store user + err = user.Insert() + if err != nil { + log.Println("Insert Error", err) + } + // Send email validation + // Create cookie session + s.NewSession(w, user.Username) + // Redirect to user profile + http.Redirect(w, r, "/u/me", http.StatusSeeOther) } } @@ -66,5 +95,16 @@ func Authenticate(s *server.Server) http.HandlerFunc { } func Show(s *server.Server) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) {} + return func(w http.ResponseWriter, r *http.Request) { + token, err := r.Cookie("session_token") + if err != nil { + s.Ui.Render(w, "user/login", &struct{ Message string }{"You are not logged in! Missing Cookie"}) + } + session, ok := s.Sessions[token.Value] + if !ok { + s.Ui.Render(w, "user/login", &struct{ Message string }{"You are not logged in! With Session."}) + } + + s.Ui.Render(w, "user/me", &struct{ Message, Username string }{"Congrats on getting this far!", session.Username()}) + } } diff --git a/src/user/user.go b/src/user/user.go index 83e39e3..e35c7c5 100644 --- a/src/user/user.go +++ b/src/user/user.go @@ -1,18 +1,73 @@ package user import ( - "errors" + "crypto/rand" + "encoding/base64" + "fmt" "time" + + "github.com/jackc/pgx/v5" + "gitlab.com/alexkavon/newsstand/src/db" + "golang.org/x/crypto/argon2" ) type User struct { Id int64 - Username string + Username string `validate:"required,max=50"` + Secret string `validate:"required,min=8,max=128"` + Email string `validate:"required,email"` Karma uint64 UpdatedAt time.Time CreatedAt time.Time + hash string + Db *db.Database +} + +func (u *User) Insert() error { + err := u.Db.InsertTable( + "users", + []string{"username", "secret", "email"}, + pgx.NamedArgs{"username": u.Username, "secret": string(u.hash), "email": u.Email}, + ) + if err != nil { + return err + } + return nil } -func NewUser(username, secret string) error { - return errors.New("Not Implemented") +func (u *User) HashSecret() error { + hashconf := &struct { + memory uint32 + iterations uint32 + parallelism uint8 + keyLength uint32 + saltLength uint32 + }{64 * 1024, 3, 2, 12, 16} + salt := make([]byte, hashconf.saltLength) + _, err := rand.Read(salt) + if err != nil { + return err + } + + hash := argon2.IDKey( + []byte(u.Secret), + salt, + hashconf.iterations, + hashconf.memory, + hashconf.parallelism, + hashconf.keyLength, + ) + b64Salt := base64.RawStdEncoding.EncodeToString(salt) + b64Hash := base64.RawStdEncoding.EncodeToString(hash) + encodedHash := fmt.Sprintf( + "$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", + argon2.Version, + hashconf.memory, + hashconf.iterations, + hashconf.parallelism, + b64Salt, + b64Hash, + ) + u.hash = encodedHash + return nil } |
