chore: added register to new interface

This commit is contained in:
Andre Henriques 2024-02-24 11:34:31 +00:00
parent 1c0d6a309b
commit 32771c7422
4 changed files with 221 additions and 28 deletions

View File

@ -385,6 +385,10 @@ func (c Context) SendJSONStatus(w http.ResponseWriter, status int, dat any) *Err
return nil return nil
} }
func (c Context) JsonBadRequest(w http.ResponseWriter, dat any) *Error {
return c.SendJSONStatus(w, http.StatusBadRequest, dat)
}
func (c Context) Error400(err error, message string, w http.ResponseWriter, path string, base string, data AnyMap) *Error { func (c Context) Error400(err error, message string, w http.ResponseWriter, path string, base string, data AnyMap) *Error {
c.SetReportCaller(true) c.SetReportCaller(true)
c.Logger.Error(message) c.Logger.Error(message)

125
users.go
View File

@ -10,6 +10,7 @@ import (
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
dbtypes "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils" . "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
) )
@ -41,7 +42,6 @@ func genToken() string {
} }
func generateToken(db *sql.DB, email string, password string) (string, bool) { func generateToken(db *sql.DB, email string, password string) (string, bool) {
row, err := db.Query("select id, salt, password from users where email = $1;", email) row, err := db.Query("select id, salt, password from users where email = $1;", email)
if err != nil || !row.Next() { if err != nil || !row.Next() {
return "", false return "", false
@ -60,7 +60,7 @@ func generateToken(db *sql.DB, email string, password string) (string, bool) {
panic("TODO handle better! Somethign is wrong with salt being stored in the database") panic("TODO handle better! Somethign is wrong with salt being stored in the database")
} }
if bcrypt.CompareHashAndPassword([]byte(db_password), append([]byte(password), bytes_salt...)) != nil { if err = bcrypt.CompareHashAndPassword([]byte(db_password), append([]byte(password), bytes_salt...)); err != nil {
return "", false return "", false
} }
@ -80,8 +80,8 @@ func usersEndpints(db *sql.DB, handle *Handle) {
if c.Mode == JSON { if c.Mode == JSON {
type UserLogin struct { type UserLogin struct {
Email string `json:email` Email string `json:"email"`
Password string `json:password` Password string `json:"password"`
} }
var dat UserLogin var dat UserLogin
@ -90,27 +90,34 @@ func usersEndpints(db *sql.DB, handle *Handle) {
return err return err
} }
/*if (dat["email"] == nil || dat["password"] == nil) {
// TODO improve this
c.Logger.Warn("Email or password are empty")
return c.Error500(nil)
}*/
// TODO Give this to the generateToken function // TODO Give this to the generateToken function
expiration := time.Now().Add(24 * time.Hour)
token, login := generateToken(db, dat.Email, dat.Password) token, login := generateToken(db, dat.Email, dat.Password)
if !login { if !login {
return c.SendJSONStatus(w, http.StatusUnauthorized, "Email or password are incorrect") return c.SendJSONStatus(w, http.StatusUnauthorized, "Email or password are incorrect")
} }
user, err := dbtypes.UserFromToken(c.Db, token)
if err != nil {
return c.Error500(err)
}
cookie := &http.Cookie{Name: "auth", Value: token, HttpOnly: false, Expires: expiration} type UserReturn struct {
http.SetCookie(w, cookie) Token string `json:"token"`
Id string `json:"id"`
UserType int `json:"user_type"`
Username string `json:"username"`
Email string `json:"email"`
}
w.Header().Set("Location", "/") userReturn := UserReturn{
w.WriteHeader(http.StatusSeeOther) Token: token,
return nil Id: user.Id,
UserType: user.UserType,
Username: user.Username,
Email: user.Email,
}
return c.SendJSON(w, userReturn)
} }
r.ParseForm() r.ParseForm()
@ -149,7 +156,87 @@ func usersEndpints(db *sql.DB, handle *Handle) {
handle.GetHTML("/register", AnswerTemplate("register.html", nil, 0)) handle.GetHTML("/register", AnswerTemplate("register.html", nil, 0))
handle.Post("/register", func(w http.ResponseWriter, r *http.Request, c *Context) *Error { handle.Post("/register", func(w http.ResponseWriter, r *http.Request, c *Context) *Error {
if c.Mode == JSON { if c.Mode == JSON {
return &Error{Code: http.StatusNotFound} type UserLogin struct {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
var dat UserLogin
if err := c.ToJSON(r, &dat); err != nil {
return err
}
if len(dat.Username) == 0 || len(dat.Password) == 0 || len(dat.Email) == 0 {
return c.SendJSONStatus(w, http.StatusBadRequest, "Please provide a valid json");
}
rows, err := db.Query("select username, email from users where username=$1 or email=$2;", dat.Username, dat.Email)
if err != nil {
return c.Error500(err);
}
defer rows.Close()
if rows.Next() {
var db_username string
var db_email string
err = rows.Scan(&db_username, &db_email)
if err != nil {
return c.Error500(err)
}
if (db_email == dat.Email) {
return c.SendJSONStatus(w, http.StatusBadRequest, "Email already in use!")
}
if (db_username == dat.Username) {
return c.SendJSONStatus(w, http.StatusBadRequest, "Username already in use!")
}
panic("Unrechable")
}
if len([]byte(dat.Password)) > 68 {
return c.JsonBadRequest(w, "Password is to long!")
}
salt := generateSalt()
hash_password, err := hashPassword(dat.Password, salt)
if err != nil {
return c.Error500(err)
}
_, err = db.Exec("insert into users (username, email, salt, password) values ($1, $2, $3, $4);", dat.Username, dat.Email, salt, hash_password)
if err != nil {
return c.Error500(err)
}
// TODO Give this to the generateToken function
token, login := generateToken(db, dat.Email, dat.Password)
if !login {
return c.SendJSONStatus(w, 500, "Could not login after creatting account please try again later")
}
user, err := dbtypes.UserFromToken(c.Db, token)
if err != nil {
return c.Error500(err)
}
type UserReturn struct {
Token string `json:"token"`
Id string `json:"id"`
UserType int `json:"user_type"`
Username string `json:"username"`
Email string `json:"email"`
}
userReturn := UserReturn{
Token: token,
Id: user.Id,
UserType: user.UserType,
Username: user.Username,
Email: user.Email,
}
return c.SendJSON(w, userReturn)
} }
r.ParseForm() r.ParseForm()
@ -264,8 +351,6 @@ func usersEndpints(db *sql.DB, handle *Handle) {
})) }))
} }
c.Logger.Warn("test", "email", r.Form.Get("email"))
_, err := c.Db.Exec("update users set email=$1 where id=$2", r.Form.Get("email"), c.User.Id) _, err := c.Db.Exec("update users set email=$1 where id=$2", r.Form.Get("email"), c.User.Id)
if err != nil { if err != nil {
return c.Error500(err) return c.Error500(err)

View File

@ -22,6 +22,7 @@
userStore.user = req; userStore.user = req;
goto("/"); goto("/");
} catch (e) { } catch (e) {
loginData.password = "";
if (e instanceof Response) { if (e instanceof Response) {
errorMessage = await e.json(); errorMessage = await e.json();
} else { } else {
@ -29,7 +30,6 @@
} }
} }
} }
</script> </script>
<svelte:head> <svelte:head>

View File

@ -0,0 +1,104 @@
<script lang="ts">
import { post } from 'src/lib/requests.svelte';
import 'src/styles/forms.css';
import { userStore } from '../UserStore.svelte';
import { goto } from '$app/navigation';
let submitted = $state(false);
let loginData = $state({
username: '',
email: '',
password: '',
});
let errorMessage = $state("");
async function onSubmit() {
submitted = true;
errorMessage = "";
try {
const req = await post('register', loginData);
userStore.user = req;
goto("/");
} catch (e) {
if (e instanceof Response) {
errorMessage = await e.json();
} else {
errorMessage = "Server could not perform login";
}
}
}
</script>
<svelte:head>
<title>
Register
</title>
</svelte:head>
<div class="login-page">
<div>
<h1>
Register
</h1>
<form on:submit|preventDefault={onSubmit} class:submitted>
<fieldset>
<label for="username">Username</label>
<input required name="username" bind:value={loginData.username} />
<!--{{if .UserError}}
<span class="form-msg error">
Username already in use
</span>
{{end}}-->
</fieldset>
<fieldset>
<label for="email">Email</label>
<input type="email" required name="email" bind:value={loginData.email} />
<!-- {{if .EmailError}}
<span class="form-msg error">
Email already in use
</span>
{{end}} -->
</fieldset>
<fieldset>
<label for="password">Password</label>
<input required name="password" type="password" bind:value={loginData.password} />
<!-- {{if .PasswordToLong}}
<span class="form-msg error">
Password is to long
</span>
{{end}} -->
</fieldset>
{#if errorMessage}
<div class="form-msg error">
{errorMessage}
</div>
{/if}
<button>
Register
</button>
<div class="spacer"></div>
<a class="simple-link text-center w100" href="/login">
Login
</a>
</form>
</div>
</div>
<style lang="scss">
.login-page {
display: grid;
place-items: center;
margin-bottom: 40px;
& > div {
width: 40vw;
}
h1 {
text-align: center;
}
}
</style>