From 527344b220944c1c054aaaa0e0b291e5b54688e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20P=C3=A9rez?= Date: Tue, 19 Nov 2024 23:17:14 +0100 Subject: [PATCH] first commit --- .idea/.gitignore | 12 ++++ go.mod | 14 +++++ go.sum | 8 +++ internal/config/config.go | 16 ++++++ internal/handlers/handlers.go | 55 +++++++++++++++++++ internal/handlers/token.go | 82 ++++++++++++++++++++++++++++ main.go | 94 ++++++++++++++++++++++++++++++++ middleware.go | 20 +++++++ router.go | 17 ++++++ static/img/dummy.png | Bin 0 -> 1785 bytes templates/component.list.gohtml | 4 ++ templates/page.index.gohtml | 52 ++++++++++++++++++ 12 files changed, 374 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/config/config.go create mode 100644 internal/handlers/handlers.go create mode 100644 internal/handlers/token.go create mode 100644 main.go create mode 100644 middleware.go create mode 100644 router.go create mode 100644 static/img/dummy.png create mode 100644 templates/component.list.gohtml create mode 100644 templates/page.index.gohtml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7373238 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,12 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml + +.idea/ +*.log +logs/ \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9457f8f --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module ron-pets + +go 1.23.2 + +replace ron => ./../ron-gola + +require ron v0.0.0-00010101000000-000000000000 + +require ( + aidanwoods.dev/go-paseto v1.5.2 // indirect + aidanwoods.dev/go-result v0.1.0 // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/sys v0.27.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fa9fb54 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +aidanwoods.dev/go-paseto v1.5.2 h1:9aKbCQQUeHCqis9Y6WPpJpM9MhEOEI5XBmfTkFMSF/o= +aidanwoods.dev/go-paseto v1.5.2/go.mod h1:7eEJZ98h2wFi5mavCcbKfv9h86oQwut4fLVeL/UBFnw= +aidanwoods.dev/go-result v0.1.0 h1:y/BMIRX6q3HwaorX1Wzrjo3WUdiYeyWbvGe18hKS3K8= +aidanwoods.dev/go-result v0.1.0/go.mod h1:yridkWghM7AXSFA6wzx0IbsurIm1Lhuro3rYef8FBHM= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..74d065a --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,16 @@ +package config + +import ( + "aidanwoods.dev/go-paseto" + "time" +) + +type App struct { + Security Security +} + +type Security struct { + AsymmetricKey paseto.V4AsymmetricSecretKey + PublicKey paseto.V4AsymmetricPublicKey + Duration time.Duration +} diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go new file mode 100644 index 0000000..4e691ba --- /dev/null +++ b/internal/handlers/handlers.go @@ -0,0 +1,55 @@ +package handlers + +import ( + "log/slog" + "ron" + "ron-pets/internal/config" +) + +type Handlers struct { + app *config.App +} + +func New(app *config.App) *Handlers { + return &Handlers{ + app: app, + } +} + +func (hq *Handlers) HelloWorld(c *ron.Context) { + slog.Info("Dummy info message") + c.W.Write([]byte("hello world")) +} + +func (hq *Handlers) AnotherHelloWorld(c *ron.Context) { + c.W.Write([]byte("another hello world")) +} + +func (hq *Handlers) HelloWorldJSON(c *ron.Context) { + id := c.R.PathValue("id") + slog.Info("path value", "id", id) + + c.JSON(200, ron.Data{"message": "hello world"}) +} + +func (hq *Handlers) HelloWorldHTML(c *ron.Context) { + + //pages := ron.Pages{ + // TotalElements: len(elements), + // ElementsPerPage: 5, + //} + // + //pages.PaginationParams(c.R) + //elementsPaginated := pages.PaginateArray(elements) + // + //td := &ron.TemplateData{ + // Data: ron.Data{"title": "hello world", "message": "hello world from html", "elements": elementsPaginated}, + // Pages: pages, + //} + // + //c.HTML(200, "page.index.gohtml", td) +} + +func (hq *Handlers) ComponentHTML(c *ron.Context) { + c.HTML(200, "component.list.gohtml", nil) +} diff --git a/internal/handlers/token.go b/internal/handlers/token.go new file mode 100644 index 0000000..860dd37 --- /dev/null +++ b/internal/handlers/token.go @@ -0,0 +1,82 @@ +package handlers + +import ( + "aidanwoods.dev/go-paseto" + "log/slog" + "net/http" + "ron" + "strings" + "time" +) + +type UserPayload struct { + User string `json:"user"` + Role string `json:"role"` +} + +func (hq *Handlers) CreateToken(c *ron.Context) { + token := paseto.NewToken() + token.Set("userPayload", UserPayload{User: "pedro", Role: "admin"}) + token.SetExpiration(time.Now().Add(hq.app.Security.Duration)) + signed := token.V4Sign(hq.app.Security.AsymmetricKey, nil) + + cookie := http.Cookie{ + Name: "token", + Value: signed, + Path: "/", + MaxAge: 3600, + HttpOnly: true, + Secure: true, + SameSite: http.SameSiteLaxMode, + } + + http.SetCookie(c.W, &cookie) + + c.JSON(http.StatusOK, ron.Data{"token": signed}) +} + +func (hq *Handlers) ValidateTokenAuthorization(c *ron.Context) { + signed := c.R.Header.Get("Authorization") + split := strings.Split(signed, "Bearer ") + slog.Info("signed", "signed", split[1]) + parser := paseto.NewParser() + token, err := parser.ParseV4Public(hq.app.Security.PublicKey, split[1], nil) + if err != nil { + slog.Error("error", "err", err) + c.JSON(http.StatusUnauthorized, ron.Data{"error": err.Error()}) + return + } + + var userPayload UserPayload + token.Get("userPayload", &userPayload) + + c.JSON(http.StatusOK, ron.Data{ + "authorized": true, + "payload": userPayload, + }) +} + +func (hq *Handlers) ValidateTokenCookie(c *ron.Context) { + cookie, err := c.R.Cookie("token") + if err != nil { + slog.Error("error", "err", err) + c.JSON(http.StatusUnauthorized, ron.Data{"error": err.Error()}) + return + } + + parser := paseto.NewParser() + token, err := parser.ParseV4Public(hq.app.Security.PublicKey, cookie.Value, nil) + if err != nil { + slog.Error("error", "err", err) + c.JSON(http.StatusUnauthorized, ron.Data{"error": err.Error()}) + return + } + + var userPayload UserPayload + token.Get("userPayload", &userPayload) + + c.JSON(http.StatusOK, ron.Data{ + "authorized": true, + "payload": userPayload, + }) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..9343665 --- /dev/null +++ b/main.go @@ -0,0 +1,94 @@ +package main + +import ( + "aidanwoods.dev/go-paseto" + "log/slog" + "ron" + "ron-pets/internal/config" + "ron-pets/internal/handlers" + "time" +) + +type SomethingElements struct { + Name string + Description string +} + +var elements = []SomethingElements{ + {"element 1", "description 1"}, + {"element 2", "description 2"}, + {"element 3", "description 3"}, + {"element 4", "description 4"}, + {"element 5", "description 5"}, + {"element 6", "description 6"}, + {"element 7", "description 7"}, + {"element 8", "description 8"}, + {"element 9", "description 9"}, + {"element 10", "description 10"}, + {"element 11", "description 11"}, + {"element 12", "description 12"}, + {"element 13", "description 13"}, + {"element 14", "description 14"}, + {"element 15", "description 15"}, + {"element 16", "description 16"}, + {"element 17", "description 17"}, + {"element 18", "description 18"}, + {"element 19", "description 19"}, + {"element 20", "description 20"}, + {"element 21", "description 21"}, + {"element 22", "description 22"}, + {"element 23", "description 23"}, + {"element 24", "description 24"}, + {"element 25", "description 25"}, + {"element 26", "description 26"}, + {"element 27", "description 27"}, + {"element 28", "description 28"}, + {"element 29", "description 29"}, + {"element 30", "description 30"}, + {"element 31", "description 31"}, + {"element 32", "description 32"}, + {"element 33", "description 33"}, + {"element 34", "description 34"}, + {"element 35", "description 35"}, + {"element 36", "description 36"}, + {"element 37", "description 37"}, + {"element 38", "description 38"}, + {"element 39", "description 39"}, + {"element 40", "description 40"}, + {"element 41", "description 41"}, + {"element 42", "description 42"}, + {"element 43", "description 43"}, + {"element 44", "description 44"}, + {"element 45", "description 45"}, + {"element 46", "description 46"}, + {"element 47", "description 47"}, + {"element 48", "description 48"}, + {"element 49", "description 49"}, +} + +var app *config.App + +func main() { + r := ron.New(func(e *ron.Engine) { + e.LogLevel = slog.LevelDebug + }) + + asymmetricKey, _ := paseto.NewV4AsymmetricSecretKeyFromHex("c3e9d207e752bd506a89e4ab09210f4b0100ddd31d3c815c0ab671f6885e9eae4def9afa5e982684329746a0718ea0a534fd9ce64813efee08c89ad6700a045d") + app = &config.App{ + Security: config.Security{ + AsymmetricKey: asymmetricKey, + PublicKey: asymmetricKey.Public(), + Duration: time.Second * 20, + }, + } + + slog.Info("asymmetric key", "key", asymmetricKey.ExportHex()) + + h := handlers.New(app) + router(h, r) + + err := r.Run(":8080") + if err != nil { + slog.Error(err.Error()) + } +} diff --git a/middleware.go b/middleware.go new file mode 100644 index 0000000..904c3a1 --- /dev/null +++ b/middleware.go @@ -0,0 +1,20 @@ +package main + +import ( + "log/slog" + "net/http" +) + +func someMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + slog.Info("triggered middleware") + next.ServeHTTP(w, r) + }) +} + +func anotherMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + slog.Info("triggered another middleware") + next.ServeHTTP(w, r) + }) +} diff --git a/router.go b/router.go new file mode 100644 index 0000000..dc86d70 --- /dev/null +++ b/router.go @@ -0,0 +1,17 @@ +package main + +import ( + "ron" + "ron-pets/internal/handlers" +) + +func router(h *handlers.Handlers, r *ron.Engine) { + htmlRender := ron.NewHTMLRender() + r.Render = htmlRender + + r.Static("static", "static") + + r.GET("/create", h.CreateToken) + r.GET("/validate", h.ValidateTokenAuthorization) + r.GET("/cookie", h.ValidateTokenCookie) +} diff --git a/static/img/dummy.png b/static/img/dummy.png new file mode 100644 index 0000000000000000000000000000000000000000..885878ca0b06af9f79305c4ba33729187a048467 GIT binary patch literal 1785 zcmb_ci&qi`7iabPc?{E)pPCw4`#zcvtj$8Fi(2L*hp*5Ov~s- zcL4x^-9cyk5CFgq6aer^{=aq_JwH3_WEqV^cyOdYgTdI|-exkH0)arGP-rxo#l^** zo}T*p`i#T*UPhSNr88(E0ATU_qkcknvv2?a{+$`*cPjFyl6R^;;$Xl&@#UCXgAKr- z*ErjW@n7s7!(O;ID%u7!9lvyM3_LG07w=Qzx8}ZWXORmW?P#alB{xrIf4W_d*;r)C zlfi4(jamLNS?Fw8+nigjUOT%iUGl2dRSCipOWoTksnc(g>f(;il0D#(h)R%QyfCGP zD(rn7ix__93o}nudxfnNbyn!K6b>c16^Ew^@joQ3u6tP95KyqGymp>uzuStIiC=xa zsI(^34&_)1Ov7kxY89RIg+&gXBOl+uuU@v!L@-Jw{I?R)HwFU}V_I}^Ei_VtxszwJ z1F-=+HcAI4)mjt{fHqV}wYq?m&uY0h+NS5i;L@iro#D1qsr#v1i|N^}lhXb*2~vJJdLk}c=M*eb}}uU3s)!i`8;?Mb*f?b6ydPE z5ek=ZTSG1i4GaUVlAXb6+i$A6-2d0Au#l_yz6&SVrA^9l!GhS9*E>+mOTqR<4#uL( zK9o6P2b?_z+Yh;DmmxPz;R~5O2fuhNItU8OrhxT5+My}dhhE5k4W3Z+#VhjDbu{mIf>|zB_l|N-1$#@*rh$`CH{Xh3DV=lEDO0`qb` zF`P|Z=rpZD^+CKbq}Cc6L8;P!I)1=f*9itja==jJ3Mz`N{F!!NNT-3T>rS*WC(2J= zA#f&y-$y_W{te*=nTRM?NlhO~$oz$fqOuwll!A?cr?5HXJBA~}!JG`csptp6#V!n5 zRxlwbmwwKYB(hfkiEv5b(TH(Y$xOkdk4VM=dk#NQO4XSOSsVPa`7LeA-8O#33)ib9 z5lg)xBj&)+_C?flouMY`TWx2O!7+V^`~ybxk$GZyxxV z?{!BWBMw`w%u^8;4?~glI|SQQ8G7?GlK9HWR|8G5-)Fz87~K{=>+vndQWiB1dqXj;C%;Ep?wm zk}+A1;>o3F@|yZY8xQJQ0HIq%3B#!(;(ZxK`e2@2-jdQx-t3Nk?BmLAMy^(RMdeXS zr_>W2Uw+)dduxPgL4blhVr}CB+<7$LE6`n9x=WkQ_pHA49O7NPV8v%m!N))Q)P=a2 zcAA*|R-fRnY7`taMpi9gct6bD>@J8)9T|xBdR@qT+jZ=t+62?P^SkscUnD<6cT(*oultXki@h01|rEmZ{`n7wLA=461oGqT~~!^k{R z7K5u{4?Sz#^onbJag5BvffM*bi7lMT`V)u)CY_up4tWkRH$0*~;BeHcT&ck9^ z%wAWw&a(F_al|J)+be*Tuj!|h`ZBOPKn#Vu( e$|JXLugd=;Z;*eeU#;(Vcm59({$IHO literal 0 HcmV?d00001 diff --git a/templates/component.list.gohtml b/templates/component.list.gohtml new file mode 100644 index 0000000..342f35f --- /dev/null +++ b/templates/component.list.gohtml @@ -0,0 +1,4 @@ +
    +
  • elem1
  • +
  • elem2
  • +
diff --git a/templates/page.index.gohtml b/templates/page.index.gohtml new file mode 100644 index 0000000..f1eef8a --- /dev/null +++ b/templates/page.index.gohtml @@ -0,0 +1,52 @@ + + + + + + {{ .Data.title }} + + + + + + +{{ .Data.message }} + +{{ range .Data.elements }} +
    + +
  • + {{ .Name }} + {{ .Description }} +
  • +
+ +{{ end }} + +{{ if not .Pages.HasPrevious }} +primera página +{{ else }} +primera +anterior +{{ end }} + +{{ range .Pages.PageRange 5 }} +{{ if .Active }} +{{ .Number }} +{{ else }} +{{ .Number }} +{{ end }} +{{ end }} + +{{ if not .Pages.HasNext }} +última página +{{ else }} +siguiente +última +{{ end }} + + + + + + \ No newline at end of file