aboutsummaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
authorAlexander Kavon <hawk@alexkavon.com>2023-11-29 02:05:38 -0500
committerAlexander Kavon <hawk@alexkavon.com>2023-11-29 02:05:38 -0500
commit1c32e1497525bc6f609898f0f79bd6cc3e6d92fb (patch)
tree99abc1c2690b151bfb3d45e9f76a8770b3597e7a /src/user
parent5e26ebc96bd41f9d232573d873cb6cb55f0050c4 (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.go56
-rw-r--r--src/user/user.go63
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
}