Skip to content

Commit a8aacea

Browse files
feat: HTTP login
1 parent c30af7f commit a8aacea

File tree

9 files changed

+162
-47
lines changed

9 files changed

+162
-47
lines changed

web/controllers/auth.go

+74-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,86 @@ package controllers
22

33
import (
44
"github.com/ItsNotGoodName/smtpbridge/internal/core"
5+
"github.com/ItsNotGoodName/smtpbridge/internal/procs"
6+
"github.com/ItsNotGoodName/smtpbridge/web/helpers"
57
"github.com/gofiber/fiber/v2"
8+
"github.com/gofiber/fiber/v2/middleware/session"
69
)
710

8-
func AuthLogin(c *fiber.Ctx, cc core.Context) error {
11+
type Flash struct {
12+
Flash string
13+
}
14+
15+
func Login(c *fiber.Ctx, cc core.Context) error {
16+
return c.Render("login", Flash{})
17+
}
18+
19+
func AuthLogin(c *fiber.Ctx, cc core.Context, store *session.Store) error {
920
// Request
21+
username := c.FormValue("username")
22+
password := c.FormValue("password")
1023

1124
// Execute
25+
err := procs.HTTPLogin(cc, username, password)
26+
if err != nil {
27+
if helpers.IsHTMXRequest(c) {
28+
return c.Render("login", Flash{Flash: err.Error()}, "form")
29+
}
30+
return c.Render("login", Flash{Flash: err.Error()})
31+
}
1232

1333
// Response
14-
return c.Render("login", fiber.Map{})
34+
sess, err := store.Get(c)
35+
if err != nil {
36+
panic(err)
37+
}
38+
39+
sess.Set("auth", true)
40+
if err := sess.Save(); err != nil {
41+
panic(err)
42+
}
43+
44+
return redirect(c, "/")
45+
}
46+
47+
func AuthLogout(c *fiber.Ctx, cc core.Context, store *session.Store) error {
48+
sess, err := store.Get(c)
49+
if err != nil {
50+
panic(err)
51+
}
52+
53+
sess.Delete("auth")
54+
if err := sess.Save(); err != nil {
55+
panic(err)
56+
}
57+
58+
return redirect(c, "/login")
59+
}
60+
61+
func AuthRequire(c *fiber.Ctx, cc core.Context, store *session.Store) error {
62+
sess, err := store.Get(c)
63+
if err != nil {
64+
panic(err)
65+
}
66+
67+
auth := sess.Get("auth")
68+
if auth == nil {
69+
return redirect(c, "/login")
70+
}
71+
72+
return c.Next()
73+
}
74+
75+
func AuthSkip(c *fiber.Ctx, cc core.Context, store *session.Store) error {
76+
sess, err := store.Get(c)
77+
if err != nil {
78+
panic(err)
79+
}
80+
81+
auth := sess.Get("auth")
82+
if auth != nil {
83+
return redirect(c, "/")
84+
}
85+
86+
return c.Next()
1587
}

web/controllers/utils.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package controllers
22

3-
import "github.com/gofiber/fiber/v2"
3+
import (
4+
"github.com/ItsNotGoodName/smtpbridge/web/helpers"
5+
"github.com/gofiber/fiber/v2"
6+
)
47

58
func checkbox(c *fiber.Ctx, key string) bool {
69
isSet := c.Query("-"+key) != ""
@@ -10,3 +13,11 @@ func checkbox(c *fiber.Ctx, key string) bool {
1013

1114
return true
1215
}
16+
func redirect(c *fiber.Ctx, path string) error {
17+
if helpers.IsHTMXRequest(c) {
18+
c.Set("HX-Location", path)
19+
return nil
20+
} else {
21+
return c.Redirect(path)
22+
}
23+
}

web/http/http.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/gofiber/fiber/v2/middleware/csrf"
1212
"github.com/gofiber/fiber/v2/middleware/logger"
1313
"github.com/gofiber/fiber/v2/middleware/recover"
14+
"github.com/gofiber/fiber/v2/middleware/session"
1415
"github.com/rs/zerolog/log"
1516
)
1617

@@ -21,6 +22,8 @@ type HTTP struct {
2122
}
2223

2324
func New(app core.App, shutdown context.CancelFunc, address string, bodyLimit int) HTTP {
25+
store := session.New()
26+
2427
// Fiber
2528
views := web.Engine()
2629
views.AddFuncMap(helpers.Map)
@@ -43,12 +46,13 @@ func New(app core.App, shutdown context.CancelFunc, address string, bodyLimit in
4346
http.Use(csrf.New(csrf.Config{
4447
KeyLookup: "cookie:csrf_",
4548
}))
49+
web.UseAssets(http)
4650

47-
// Routes
48-
routes(http, app)
51+
route(app,
52+
store,
53+
http,
54+
)
4955

50-
// Middleware
51-
web.UseAssets(http)
5256
http.Use(helpers.NotFound)
5357

5458
return HTTP{

web/http/routes.go

+30-23
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,59 @@ package http
33
import (
44
"github.com/ItsNotGoodName/smtpbridge/internal/core"
55
"github.com/ItsNotGoodName/smtpbridge/web/controllers"
6-
"github.com/ItsNotGoodName/smtpbridge/web/middleware"
6+
"github.com/ItsNotGoodName/smtpbridge/web/inject"
77
"github.com/gofiber/fiber/v2"
8+
"github.com/gofiber/fiber/v2/middleware/session"
89
)
910

10-
func routes(http *fiber.App, app core.App) {
11-
http.Get("/", middleware.App(app, controllers.Index))
11+
func route(app core.App, store *session.Store, http fiber.Router) {
12+
authSkip := inject.AppStore(app, store, controllers.AuthSkip)
13+
authRequire := inject.AppStore(app, store, controllers.AuthRequire)
14+
15+
http.Get("/login", authSkip, inject.App(app, controllers.Login))
16+
http.Post("/auth", authSkip, inject.AppStore(app, store, controllers.AuthLogin))
17+
http.Delete("/auth", authRequire, inject.AppStore(app, store, controllers.AuthLogout))
18+
19+
http.Get("/", authRequire, inject.App(app, controllers.Index))
1220
http.Route("/index", func(http fiber.Router) {
13-
http.Get("/storage-table", middleware.App(app, controllers.IndexStorageTable))
14-
http.Get("/recent-envelopes-table", middleware.App(app, controllers.IndexRecentEnvelopesTable))
21+
http.Get("/storage-table", authRequire, inject.App(app, controllers.IndexStorageTable))
22+
http.Get("/recent-envelopes-table", authRequire, inject.App(app, controllers.IndexRecentEnvelopesTable))
1523
})
1624

17-
http.Get("/login", middleware.App(app, controllers.AuthLogin))
18-
1925
http.Route("/envelopes", func(http fiber.Router) {
20-
http.Get("/", middleware.App(app, controllers.Envelopes))
21-
http.Delete("/", middleware.App(app, controllers.EnvelopesDelete))
22-
http.Get("/new", controllers.EnvelopeNew)
23-
http.Post("/new", middleware.App(app, controllers.EnvelopeNewPost))
26+
http.Get("/", authRequire, inject.App(app, controllers.Envelopes))
27+
http.Delete("/", authRequire, inject.App(app, controllers.EnvelopesDelete))
28+
http.Get("/new", authRequire, controllers.EnvelopeNew)
29+
http.Post("/new", authRequire, inject.App(app, controllers.EnvelopeNewPost))
2430
http.Route("/:id", func(http fiber.Router) {
25-
http.Get("/", middleware.AppID(app, controllers.Envelope))
26-
http.Delete("/", middleware.AppID(app, controllers.EnvelopeDelete))
27-
http.Get("/html", middleware.AppID(app, controllers.EnvelopeHTML))
31+
http.Get("/", authRequire, inject.AppID(app, controllers.Envelope))
32+
http.Delete("/", authRequire, inject.AppID(app, controllers.EnvelopeDelete))
33+
http.Get("/html", authRequire, inject.AppID(app, controllers.EnvelopeHTML))
2834
})
2935
})
3036

3137
http.Route("/attachments", func(http fiber.Router) {
32-
http.Get("/", middleware.App(app, controllers.Attachments))
38+
http.Get("/", authRequire, inject.App(app, controllers.Attachments))
3339
})
3440

3541
http.Route("/endpoints", func(http fiber.Router) {
36-
http.Get("/", middleware.App(app, controllers.Endpoints))
42+
http.Get("/", authRequire, inject.App(app, controllers.Endpoints))
3743
http.Route("/:id", func(http fiber.Router) {
38-
http.Post("/test", middleware.AppID(app, controllers.EndpointTest))
44+
http.Post("/test", authRequire, inject.AppID(app, controllers.EndpointTest))
3945
})
4046
})
4147

4248
http.Route("/rules", func(http fiber.Router) {
43-
http.Get("/", middleware.App(app, controllers.Rules))
49+
http.Get("/", authRequire, inject.App(app, controllers.Rules))
4450
http.Route("/:id", func(http fiber.Router) {
45-
http.Post("/enable", middleware.AppID(app, controllers.RuleEnable))
51+
http.Post("/enable", authRequire, inject.AppID(app, controllers.RuleEnable))
4652
})
4753
})
4854

49-
http.Post("/send", middleware.App(app, controllers.Send))
50-
http.Post("/vacuum", middleware.App(app, controllers.Vacuum))
51-
http.Post("/trim", middleware.App(app, controllers.Trim))
52-
http.Group("/files", controllers.Files(app))
55+
http.Post("/send", authRequire, inject.App(app, controllers.Send))
56+
http.Post("/vacuum", authRequire, inject.App(app, controllers.Vacuum))
57+
http.Post("/trim", authRequire, inject.App(app, controllers.Trim))
58+
http.Group("/files", authRequire, controllers.Files(app))
59+
5360
http.Get("/something-went-wrong", controllers.SomethingWentWrong)
5461
}
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
package middleware
1+
package inject
22

33
import (
4-
"context"
54
"net/http"
65
"strconv"
76

87
"github.com/ItsNotGoodName/smtpbridge/internal/core"
98
"github.com/ItsNotGoodName/smtpbridge/web/helpers"
109
"github.com/gofiber/fiber/v2"
10+
"github.com/gofiber/fiber/v2/middleware/session"
1111
)
1212

1313
func App(app core.App, fn func(c *fiber.Ctx, cc core.Context) error) fiber.Handler {
1414
return func(c *fiber.Ctx) error {
15-
return fn(c, app.Context(context.Background()))
15+
return fn(c, app.Context(c.Context()))
1616
}
1717
}
1818

@@ -23,6 +23,12 @@ func AppID(app core.App, fn func(c *fiber.Ctx, cc core.Context, id int64) error)
2323
return helpers.Error(c, err, http.StatusBadRequest)
2424
}
2525

26-
return fn(c, app.Context(context.Background()), id)
26+
return fn(c, app.Context(c.Context()), id)
27+
}
28+
}
29+
30+
func AppStore(app core.App, store *session.Store, fn func(c *fiber.Ctx, cc core.Context, store *session.Store) error) fiber.Handler {
31+
return func(c *fiber.Ctx) error {
32+
return fn(c, app.Context(c.Context()), store)
2733
}
2834
}

web/views/404.html

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
{{template "partials/header" .}}
2-
31
<main class="container">
42
<div>404 Not Found</div>
53
</main>
6-
7-
{{template "partials/footer" .}}

web/views/login.html

+12-3
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,28 @@ <h1>SMTPBridge</h1>
77

88
<article class="max-w-md mx-auto">
99
<h2>Login</h2>
10-
<form method="post">
10+
{{block "form" .}}
11+
<form method="post" action="/auth" hx-post="/auth" hx-swap="outerHTML">
1112
<label for="username">
1213
Username
1314
<input type="text" id="username" name="username" placeholder="Username" />
1415
</label>
1516

1617
<label for="password">
1718
Password
18-
<input type="text" id="password" name="password" placeholder="Password" />
19+
<input type="password" id="password" name="password" placeholder="Password" />
1920
</label>
2021

21-
<button type="submit">Log in</button>
22+
<button data-loading-path="/login" data-loading-disable data-loading-aria-busy>
23+
Log in
24+
</button>
25+
{{with .Flash}}
26+
<h3>
27+
{{.}}
28+
</h3>
29+
{{end}}
2230
</form>
31+
{{end}}
2332
</article>
2433
</main>
2534

web/views/partials/header.html

+16-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</a>
99
</li>
1010
</ul>
11-
<ul class=" block md:hidden">
11+
<ul class=" block lg:hidden">
1212
<li class="p-0 flex flex-items-center h-full">
1313
<details role="list" dir="rtl">
1414
<summary aria-haspopup="listbox" class="block pico-no-chevron">
@@ -43,11 +43,18 @@
4343
</div>
4444
</a>
4545
</li>
46+
<li>
47+
<a href="#" class="contrast" hx-delete="/auth">
48+
<div class="flex flex-items-center flex-row-reverse gap-2">
49+
<div class="i-ri-logout-box-r-fill"></div>Log out
50+
</div>
51+
</a>
52+
</li>
4653
</ul>
4754
</details>
4855
</li>
4956
</ul>
50-
<ul class="hidden md:block">
57+
<ul class="hidden lg:block">
5158
<li>
5259
<a href="/envelopes" class="contrast">
5360
<div class="flex flex-items-center gap-2">
@@ -76,6 +83,13 @@
7683
</div>
7784
</a>
7885
</li>
86+
<li>
87+
<a href="#" class="contrast" hx-delete="/auth">
88+
<div class="flex flex-items-center gap-2">
89+
<div class="i-ri-logout-box-r-fill"></div>Log out
90+
</div>
91+
</a>
92+
</li>
7993
</ul>
8094
</nav>
8195
</div>

web/views/something-went-wrong.html

-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
{{template "partials/header" .}}
2-
31
<main class="container">
42
<section>
53
<div>Something went wrong.</div>
@@ -8,5 +6,3 @@
86
{{end}}
97
</section>
108
</main>
11-
12-
{{template "partials/footer" .}}

0 commit comments

Comments
 (0)