diff --git a/go.mod b/go.mod index aeb88d6..618df2d 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ require ( gorm.io/gorm v1.25.12 ) +require github.com/go-resty/resty/v2 v2.15.3 // indirect + require ( github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/go.sum b/go.sum index a4ac02d..d588963 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8= +github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/public/css/input.css b/public/css/input.css index b5c61c9..a8eb458 100644 --- a/public/css/input.css +++ b/public/css/input.css @@ -1,3 +1,9 @@ @tailwind base; @tailwind components; @tailwind utilities; + +body { + font-family: "Atkinson Hyperlegible", sans-serif; +} + + diff --git a/src/modules/auth/setup.go b/src/modules/auth/setup.go index 8dc3b0e..2c59f9f 100644 --- a/src/modules/auth/setup.go +++ b/src/modules/auth/setup.go @@ -7,13 +7,6 @@ import ( "gorm.io/gorm" ) -// Represents a User in the Database -type User struct { - gorm.Model - Name string - Password string -} - // A package-level database handle. // It is set up by the [SetupSchema] func, // which should be called before the webserver @@ -23,8 +16,6 @@ var db *gorm.DB // Creates all the database tables that this module requires, // and sets up the database handle for this module func SetupSchema(dbHandle *gorm.DB) { - dbHandle.AutoMigrate(&User{}) - db = dbHandle } // Registers all the routes that this module (auth) provides diff --git a/src/modules/index/index.go b/src/modules/index/index.go new file mode 100644 index 0000000..a3ca9d7 --- /dev/null +++ b/src/modules/index/index.go @@ -0,0 +1,59 @@ +package index + +import ( + "acide/src/utils" + "fmt" + "log" + "net/http" + "time" + + "github.com/labstack/echo" +) + +// Registers all the routes that this module (auth) provides +func SetupRoutes(g *echo.Group) { + log.Print("Setting up the index module") + + // To include custom rendering logic: + g.GET("/", index) + g.POST("/f/login", loginFragment) +} + +func index(c echo.Context) error { + return utils.RenderTempl(c, http.StatusOK, IndexTempl()) +} + +func loginFragment(c echo.Context) error { + + navidromeServer := c.FormValue("navidrome-url") + username := c.FormValue("username") + password := c.FormValue("password") + + // TODO: validation + + sessionToken, err := login(navidromeServer, username, password) + if err != nil { + errorMessage := fmt.Sprintf("
Error logging in: %s
", err) + return c.HTML(http.StatusBadRequest, errorMessage) + } + + cookie1 := new(http.Cookie) + cookie1.Name = "session-token" + cookie1.Value = sessionToken + cookie1.Expires = time.Now().Add(24 * time.Hour) + cookie1.Path = "/" + cookie1.HttpOnly = true + cookie1.Secure = true + c.SetCookie(cookie1) + + cookie2 := new(http.Cookie) + cookie2.Name = "navidrome-url" + cookie2.Value = navidromeServer + cookie2.Expires = time.Now().Add(24 * time.Hour) + cookie2.Path = "/" + cookie2.HttpOnly = true + cookie2.Secure = true + c.SetCookie(cookie2) + + return c.HTML(http.StatusOK, "wrote some cookies :D") +} diff --git a/src/modules/index/index.templ b/src/modules/index/index.templ new file mode 100644 index 0000000..02a6b96 --- /dev/null +++ b/src/modules/index/index.templ @@ -0,0 +1,64 @@ +package index + +import "acide/src/utils" + +templ IndexTempl() { + @utils.SkeletonTempl() { + +
+ Login to Navidrome: +
+
+ + +
+ + +
+ + +
+ +
+
+ Result: +
+
+
+ } +} diff --git a/src/modules/index/index_templ.go b/src/modules/index/index_templ.go new file mode 100644 index 0000000..4e6d460 --- /dev/null +++ b/src/modules/index/index_templ.go @@ -0,0 +1,60 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.2.778 +package index + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "acide/src/utils" + +func IndexTempl() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
Login to Navidrome:




Result:
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) + templ_7745c5c3_Err = utils.SkeletonTempl().Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return templ_7745c5c3_Err + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/src/modules/index/login.go b/src/modules/index/login.go new file mode 100644 index 0000000..83b5e97 --- /dev/null +++ b/src/modules/index/login.go @@ -0,0 +1,41 @@ +package index + +import ( + "acide/src/utils" + "errors" + "fmt" + + "github.com/go-resty/resty/v2" +) + +type AuthError struct { + Error string `json:"error"` +} + +// Attempts to login to a navidrome server with the provided credentials. +// Returns the session key if succesful, an error otherwise +func login(server, username, password string) (string, error) { + client := resty.New() + + var loginData utils.AuthSuccess + var loginError AuthError + + response, err := client.R(). + SetHeader("Content-Type", ""). + SetBody(fmt.Sprintf(`{"username":"%s","password":"%s"}`, username, password)). + SetResult(&loginData). + SetError(&loginError). + Post(fmt.Sprintf("%s/auth/login", server)) + + if err != nil { + return "", err + } + + if !response.IsSuccess() { + return "", errors.New(loginError.Error) + } + + var sessionToken = loginData.Token + + return sessionToken, nil +} diff --git a/src/routes.go b/src/routes.go index c8824fe..859dbbd 100644 --- a/src/routes.go +++ b/src/routes.go @@ -2,6 +2,7 @@ package src import ( "acide/src/modules/auth" + "acide/src/modules/index" "net/http" "os" @@ -9,7 +10,7 @@ import ( "github.com/labstack/echo/middleware" ) -var dev = os.Getenv("DEV") != "" +var dev = os.Getenv("APP_ENV") == "dev" // Sets up the Echo server, and registers all routes and sub routes func (s *Server) RegisterRoutes() http.Handler { @@ -23,14 +24,10 @@ func (s *Server) RegisterRoutes() http.Handler { http.FileServer(http.Dir("public")))) e.GET("/public/*", echo.WrapHandler(staticFilesFolder)) - // TODO: Register subroutes here - // login.SetupRoutes(e.Group("/auth")) + // NOTE: Register subroutes here + index.SetupRoutes(e.Group("")) auth.SetupRoutes(e.Group("/auth")) - e.GET("/", func(ctx echo.Context) error { - return ctx.String(http.StatusOK, "Hello") - }) - return e } diff --git a/src/server.go b/src/server.go index a927651..ec8b4d6 100644 --- a/src/server.go +++ b/src/server.go @@ -1,7 +1,6 @@ package src import ( - "acide/src/database" "fmt" "net/http" "os" @@ -9,13 +8,10 @@ import ( "time" _ "github.com/joho/godotenv/autoload" - - "gorm.io/gorm" ) type Server struct { port int - db *gorm.DB } // Creates a new Server @@ -28,7 +24,6 @@ func NewServer() *http.Server { NewServer := &Server{ port: port, - db: database.New(), } // TODO: Register DB schemas here diff --git a/src/utils/types.go b/src/utils/types.go new file mode 100644 index 0000000..b0939a5 --- /dev/null +++ b/src/utils/types.go @@ -0,0 +1,12 @@ +package utils + +// The result of a Login +type AuthSuccess struct { + Id string `json:"id"` + IsAdmin bool `json:"isAdmin"` + Name string `json:"name"` + SubsonicSalt string `json:"subsonicSalt"` + SubsonicToken string `json:"subsonicToken"` + Token string `json:"token"` + Username string `json:"username"` +} diff --git a/src/utils/utils.templ b/src/utils/utils.templ index c39bc52..59b23ce 100644 --- a/src/utils/utils.templ +++ b/src/utils/utils.templ @@ -7,7 +7,13 @@ templ SkeletonTempl() { Acide Template + + + + + +
diff --git a/src/utils/utils_templ.go b/src/utils/utils_templ.go index 6e6bc93..104eea2 100644 --- a/src/utils/utils_templ.go +++ b/src/utils/utils_templ.go @@ -29,7 +29,7 @@ func SkeletonTempl() templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Acide Template
") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("Acide Template
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/tailwind.config.cjs b/tailwind.config.cjs index d19aa78..9898a0a 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -1,7 +1,7 @@ /** @type {import('tailwindcss').Config} */ export default { content: [ - "./src/**/*.{html,templ}", + "./src/**/*.{html,templ,go}", ], theme: { extend: {},