schema migration and account fixes
very close to rolling this out! just need to address some security concerns first
This commit is contained in:
parent
5566a795da
commit
570cdf6ce2
20 changed files with 641 additions and 392 deletions
|
@ -35,25 +35,35 @@ func handleLogin() http.HandlerFunc {
|
|||
|
||||
account, err := controller.GetAccount(global.DB, credentials.Username)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no rows") {
|
||||
http.Error(w, "Invalid username or password", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to retrieve account: %s\n", err.Error())
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to retrieve account: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if account == nil {
|
||||
http.Error(w, "Invalid username or password", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword(account.Password, []byte(credentials.Password))
|
||||
err = bcrypt.CompareHashAndPassword([]byte(account.Password), []byte(credentials.Password))
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid username or password", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: sessions and tokens
|
||||
token, err := controller.CreateToken(global.DB, account.ID, r.UserAgent())
|
||||
type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("Logged in successfully. TODO: Session tokens\n"))
|
||||
err = json.NewEncoder(w).Encode(LoginResponse{
|
||||
Token: token.Token,
|
||||
ExpiresAt: token.ExpiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to return session token: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -68,7 +78,7 @@ func handleAccountRegistration() http.HandlerFunc {
|
|||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Code string `json:"code"`
|
||||
Invite string `json:"invite"`
|
||||
}
|
||||
|
||||
credentials := RegisterRequest{}
|
||||
|
@ -79,50 +89,65 @@ func handleAccountRegistration() http.HandlerFunc {
|
|||
}
|
||||
|
||||
// make sure code exists in DB
|
||||
invite := model.Invite{}
|
||||
err = global.DB.Get(&invite, "SELECT * FROM invite WHERE code=$1", credentials.Code)
|
||||
invite, err := controller.GetInvite(global.DB, credentials.Invite)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "no rows") {
|
||||
http.Error(w, "Invalid invite code", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to retrieve invite: %s\n", err.Error())
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to retrieve invite: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if invite == nil {
|
||||
http.Error(w, "Invalid invite code", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if time.Now().After(invite.ExpiresAt) {
|
||||
err := controller.DeleteInvite(global.DB, invite.Code)
|
||||
if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to delete expired invite: %v\n", err) }
|
||||
http.Error(w, "Invalid invite code", http.StatusBadRequest)
|
||||
_, err = global.DB.Exec("DELETE FROM invite WHERE code=$1", credentials.Code)
|
||||
if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to delete expired invite: %s\n", err.Error()) }
|
||||
return
|
||||
}
|
||||
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to generate password hash: %s\n", err.Error())
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to generate password hash: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
account := model.Account{
|
||||
Username: credentials.Username,
|
||||
Password: hashedPassword,
|
||||
Password: string(hashedPassword),
|
||||
Email: credentials.Email,
|
||||
AvatarURL: "/img/default-avatar.png",
|
||||
}
|
||||
err = controller.CreateAccount(global.DB, &account)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to create account: %s\n", err.Error())
|
||||
if strings.HasPrefix(err.Error(), "pq: duplicate key") {
|
||||
http.Error(w, "An account with that username already exists", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to create account: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = global.DB.Exec("DELETE FROM invite WHERE code=$1", credentials.Code)
|
||||
if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to delete expired invite: %s\n", err.Error()) }
|
||||
err = controller.DeleteInvite(global.DB, invite.Code)
|
||||
if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to delete expired invite: %v\n", err) }
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte("Account created successfully\n"))
|
||||
token, err := controller.CreateToken(global.DB, account.ID, r.UserAgent())
|
||||
type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt time.Time `json:"expires_at"`
|
||||
}
|
||||
|
||||
err = json.NewEncoder(w).Encode(LoginResponse{
|
||||
Token: token.Token,
|
||||
ExpiresAt: token.ExpiresAt,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to return session token: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -151,20 +176,22 @@ func handleDeleteAccount() http.HandlerFunc {
|
|||
http.Error(w, "Invalid username or password", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to retrieve account: %s\n", err.Error())
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to retrieve account: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword(account.Password, []byte(credentials.Password))
|
||||
err = bcrypt.CompareHashAndPassword([]byte(account.Password), []byte(credentials.Password))
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid username or password", http.StatusBadRequest)
|
||||
http.Error(w, "Invalid password", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = controller.DeleteAccount(global.DB, account.ID)
|
||||
// TODO: check TOTP
|
||||
|
||||
err = controller.DeleteAccount(global.DB, account.Username)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to delete account: %s\n", err.Error())
|
||||
fmt.Fprintf(os.Stderr, "WARN: Failed to delete account: %v\n", err)
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue