auth with jwt

This commit is contained in:
GitBluub
2024-05-04 22:03:58 +02:00
parent 12398f8065
commit 4a0b3157c4
4 changed files with 190 additions and 51 deletions
+39 -3
View File
@@ -1,8 +1,44 @@
package main
import huh "github.com/charmbracelet/huh"
import (
huh "github.com/charmbracelet/huh"
)
type Auth struct {
form *huh.Form
jwt *string
loginForm *huh.Form
registerForm *huh.Form
jwt *string
}
func getLoginForm() *huh.Form {
return huh.NewForm(
huh.NewGroup(
huh.NewInput().
Title("Email").
Key("email"),
huh.NewInput().
Title("Password").
Key("password").
Password(true),
)).WithWidth(40)
}
func getRegisterForm() *huh.Form {
return huh.NewForm(
huh.NewGroup(
huh.NewInput().
Title("Email").
Key("email"),
huh.NewInput().
Title("Username").
Key("username"),
huh.NewInput().
Title("Password").
Key("password").
Password(true),
huh.NewInput().
Title("Repeat Password").
Key("password_repeat").
Password(true),
)).WithWidth(40)
}
+85 -9
View File
@@ -1,9 +1,11 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
tea "github.com/charmbracelet/bubbletea"
@@ -17,17 +19,91 @@ type missingJwtMsg struct{}
func (e errMsg) Error() string { return e.error.Error() }
type getEntriesSuccessMsg []Entry
type getEntriesErrMsg error
type httpErrorMsg error
const serverUrl = "localhost:3000"
const serverUrl = "http://localhost:1597"
type loginSuccessMsg struct{ string }
type registerSuccessMsg struct{ string }
func getData(req *http.Request) ([]byte, error) {
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Print("err", err)
return nil, httpErrorMsg(err)
}
defer resp.Body.Close() // nolint: errcheck
data, err := io.ReadAll(resp.Body)
log.Print("body", resp.Body)
if err != nil {
return nil, httpErrorMsg(err)
}
return data, nil
}
func login(username string, password string) tea.Cmd {
return func() tea.Msg {
_ = username
_ = password
return loginSuccessMsg{"dawdaw"}
url := fmt.Sprintf("%s/login", serverUrl)
body := struct {
Name string `json:"email"`
Password string `json:"password"`
}{
Name: username, Password: password,
}
out, err := json.Marshal(body)
if err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(out))
req.Header.Add("Content-type", "application/json")
data, err := getData(req)
if err != nil {
return err
}
var loginResp AuthRes
err = json.Unmarshal(data, &loginResp)
if err != nil {
return httpErrorMsg(err)
}
return loginSuccessMsg{loginResp.Token}
}
}
type AuthRes struct {
Token string `json:"token"`
}
func register(username string, password string, email string) tea.Cmd {
return func() tea.Msg {
url := fmt.Sprintf("%s/register", serverUrl)
body := struct {
Name string `json:"name"`
Password string `json:"password"`
Email string `json:"email"`
}{
Name: username, Password: password, Email: email,
}
out, err := json.Marshal(body)
if err != nil {
log.Fatal(err)
}
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(out))
req.Header.Add("Content-type", "application/json")
data, err := getData(req)
if err != nil {
return err
}
var registerResp AuthRes
err = json.Unmarshal(data, &registerResp)
if err != nil {
return httpErrorMsg(err)
}
return registerSuccessMsg{registerResp.Token}
}
}
@@ -42,25 +118,25 @@ func getEntries(jwt *string) tea.Cmd {
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", *jwt))
if err != nil {
return getEntriesErrMsg(err)
return httpErrorMsg(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return getEntriesErrMsg(err)
return httpErrorMsg(err)
}
defer resp.Body.Close() // nolint: errcheck
data, err := io.ReadAll(resp.Body)
if err != nil {
return getEntriesErrMsg(err)
return httpErrorMsg(err)
}
var entries []Entry
err = json.Unmarshal(data, &entries)
if err != nil {
return getEntriesErrMsg(err)
return httpErrorMsg(err)
}
return getEntriesSuccessMsg(entries)
+47 -33
View File
@@ -39,31 +39,12 @@ type Model struct {
}
func New() *Model {
loginForm := huh.NewForm(
huh.NewGroup(
huh.NewInput().
Title("Username").
Key("username"),
// Validating fields is easy. The form will mark erroneous fields
// and display error messages accordingly.
// TODO:
// Validate(func(str string) error {
// if str == "octopus773" {
// return errors.New("Not you")
// }
// return nil
// })))
huh.NewInput().
Title("Password").
Key("password").
Password(true),
))
ti := textinput.New()
ti.Placeholder = "Pikachu"
ti.Focus()
ti.CharLimit = 156
ti.Width = 56
return &Model{textInput: ti, auth: Auth{form: loginForm, jwt: new(string)}, page: "LOGIN"}
return &Model{textInput: ti, auth: Auth{loginForm: getLoginForm(), registerForm: getRegisterForm(), jwt: new(string)}, page: LOGIN}
}
func (m Model) getEverything() tea.Cmd {
@@ -85,7 +66,7 @@ func (m *Model) initList(width int, height int) {
}
func (m Model) Init() tea.Cmd {
return tea.Batch(checkServer, m.auth.form.Init())
return tea.Batch(checkServer, m.auth.loginForm.Init(), m.auth.registerForm.Init())
}
@@ -194,37 +175,70 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case loginSuccessMsg:
*m.auth.jwt = msg.string
m.page = FEEDS
return m, nil
case registerSuccessMsg:
*m.auth.jwt = msg.string
m.page = FEEDS
return m, nil
case tea.KeyMsg:
switch msg.Type {
case tea.KeyCtrlC, tea.KeyEsc:
return m, tea.Quit
case tea.KeyCtrlT:
if m.page == LOGIN {
m.page = REGISTER
} else if m.page == REGISTER {
m.page = LOGIN
}
}
switch {
case key.Matches(msg, m.textInput.KeyMap.DeleteCharacterBackward):
case key.Matches(msg, m.textInput.KeyMap.DeleteCharacterBackward): //TODO: add only when query
words := strings.Split(m.textInput.Value(), " ")
if len(words) > 0 && (strings.HasPrefix(words[len(words)-1], "tag:") || strings.HasPrefix(words[len(words)-1], "feed:")) {
m.deleteWordBackward()
}
}
// if writing
}
var cmds []tea.Cmd
// Process the form
form, cmd := m.auth.form.Update(msg)
if f, ok := form.(*huh.Form); ok {
m.auth.form = f
cmds = append(cmds, cmd)
// LOGIN
if m.page == LOGIN {
form, cmd := m.auth.loginForm.Update(msg)
if f, ok := form.(*huh.Form); ok {
m.auth.loginForm = f
cmds = append(cmds, cmd)
}
if m.auth.loginForm.State == huh.StateCompleted {
username := m.auth.loginForm.GetString("email")
password := m.auth.loginForm.GetString("password")
cmds = append(cmds, login(username, password))
}
}
if m.auth.form.State == huh.StateCompleted {
// Quit when the form is done.
username := m.auth.form.GetString("username")
password := m.auth.form.GetString("password")
cmds = append(cmds, login(username, password))
}
if m.page == REGISTER {
// Process the form
// LOGIN
registerForm, cmd := m.auth.registerForm.Update(msg)
if f, ok := registerForm.(*huh.Form); ok {
m.auth.registerForm = f
cmds = append(cmds, cmd)
}
if m.auth.registerForm.State == huh.StateCompleted {
username := m.auth.registerForm.GetString("username")
password := m.auth.registerForm.GetString("password")
email := m.auth.registerForm.GetString("email")
cmds = append(cmds, register(username, password, email))
}
}
var cmd tea.Cmd
m.list, cmd = m.list.Update(msg)
cmds = append(cmds, cmd)
m.textInput, cmd = m.textInput.Update(msg)
+19 -6
View File
@@ -1,22 +1,33 @@
package main
import (
"fmt"
"github.com/charmbracelet/lipgloss"
)
const (
LOGIN = "LOGIN"
ENTRIES = "ENTRIES"
FEEDS = "FEEDS"
TAGS = "TAGS"
LOGIN = "LOGIN"
REGISTER = "REGISTER"
ENTRIES = "ENTRIES"
FEEDS = "FEEDS"
TAGS = "TAGS"
)
type VexPage string
func (m Model) LoginView() string {
return m.auth.form.View()
return lipgloss.JoinHorizontal(
lipgloss.Left,
m.auth.loginForm.View(),
m.auth.registerForm.View(),
)
}
func (m Model) EntriesView() string {
return ""
}
func (m Model) FeedsView() string {
return "feeds"
return fmt.Sprintf("%s ", *m.auth.jwt)
}
func (m Model) TagsView() string {
return ""
@@ -25,6 +36,8 @@ func (m Model) View() string {
switch m.page {
case LOGIN:
return m.LoginView()
case REGISTER:
return m.LoginView()
case ENTRIES:
return m.EntriesView()
case FEEDS: