feat: make app configurable

This commit is contained in:
Stavros
2025-01-19 15:04:46 +02:00
parent c0e085ea10
commit 6eccb6d835
11 changed files with 299 additions and 40 deletions

View File

@@ -6,22 +6,36 @@ import (
"net/http"
"os"
"strings"
"time"
"tinyauth/internal/assets"
"tinyauth/internal/auth"
"tinyauth/internal/types"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/google/go-querystring/query"
"github.com/rs/zerolog/log"
)
func Run() {
router := gin.Default()
dist, _ := fs.Sub(assets.Assets, "dist")
func Run(config types.Config, users types.UserList) {
gin.SetMode(gin.ReleaseMode)
router := gin.New()
router.Use(zerolog())
dist, distErr := fs.Sub(assets.Assets, "dist")
if distErr != nil {
log.Fatal().Err(distErr).Msg("Failed to get UI assets")
os.Exit(1)
}
fileServer := http.FileServer(http.FS(dist))
store := cookie.NewStore([]byte("secret"))
store := cookie.NewStore([]byte(config.Secret))
domain := strings.Split(config.RootURL, "://")[1]
store.Options(sessions.Options{
Domain: ".dev.local",
Domain: fmt.Sprintf(".%s", domain),
Path: "/",
})
router.Use(sessions.Sessions("tinyauth", store))
@@ -40,22 +54,36 @@ func Run() {
router.GET("/api/auth", func (c *gin.Context) {
session := sessions.Default(c)
value := session.Get("tinyauth")
if value == nil || value != "true" {
uri := c.Request.Header.Get("X-Forwarded-Uri")
proto := c.Request.Header.Get("X-Forwarded-Proto")
host := c.Request.Header.Get("X-Forwarded-Host")
queries := types.LoginQuery{
RedirectURI: fmt.Sprintf("%s://%s%s", proto, host, uri),
if value != nil {
usernameString, ok := value.(string)
if ok {
if auth.FindUser(users, usernameString) != nil {
c.JSON(200, gin.H{
"status": 200,
"message": "Authorized",
})
return
}
}
values, _ := query.Values(queries)
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("http://tinyauth.dev.local?%s", values.Encode()))
}
c.JSON(200, gin.H{
"status": 200,
"message": "Authorized",
uri := c.Request.Header.Get("X-Forwarded-Uri")
proto := c.Request.Header.Get("X-Forwarded-Proto")
host := c.Request.Header.Get("X-Forwarded-Host")
queries, queryErr := query.Values(types.LoginQuery{
RedirectURI: fmt.Sprintf("%s://%s%s", proto, host, uri),
})
if queryErr != nil {
c.JSON(501, gin.H{
"status": 501,
"message": "Internal Server Error",
})
return
}
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/?%s", config.AppURL, queries.Encode()))
})
router.POST("/api/login", func (c *gin.Context) {
@@ -71,7 +99,17 @@ func Run() {
return
}
if login.Email != "user@example.com" || login.Password != "password" {
user := auth.FindUser(users, login.Username)
if user == nil {
c.JSON(401, gin.H{
"status": 401,
"message": "Unauthorized",
})
return
}
if !auth.CheckPassword(*user, login.Password) {
c.JSON(401, gin.H{
"status": 401,
"message": "Unauthorized",
@@ -80,7 +118,7 @@ func Run() {
}
session := sessions.Default(c)
session.Set("tinyauth", "true")
session.Set("tinyauth", user.Username)
session.Save()
c.JSON(200, gin.H{
@@ -104,19 +142,50 @@ func Run() {
session := sessions.Default(c)
value := session.Get("tinyauth")
if value == nil || value != "true" {
c.JSON(200, gin.H{
"status": 200,
"isLoggedIn": false,
})
return
if value != nil {
usernameString, ok := value.(string)
if ok {
if auth.FindUser(users, usernameString) != nil {
c.JSON(200, gin.H{
"status": 200,
"isLoggedIn": true,
"username": usernameString,
})
return
}
}
}
c.JSON(200, gin.H{
"status": 200,
"isLoggedIn": true,
"isLoggedIn": false,
"username": "",
})
})
router.Run(":3000")
router.Run(fmt.Sprintf("%s:%d", config.Address, config.Port))
}
func zerolog() gin.HandlerFunc {
return func(c *gin.Context) {
tStart := time.Now()
c.Next()
code := c.Writer.Status()
address := c.Request.RemoteAddr
method := c.Request.Method
path := c.Request.URL.Path
latency := time.Since(tStart).String()
switch {
case code >= 200 && code < 300:
log.Info().Str("method", method).Str("path", path).Str("address", address).Int("status", code).Str("latency", latency).Msg("Request")
case code >= 300 && code < 400:
log.Warn().Str("method", method).Str("path", path).Str("address", address).Int("status", code).Str("latency", latency).Msg("Request")
case code >= 400:
log.Error().Str("method", method).Str("path", path).Str("address", address).Int("status", code).Str("latency", latency).Msg("Request")
}
}
}

21
internal/auth/auth.go Normal file
View File

@@ -0,0 +1,21 @@
package auth
import (
"tinyauth/internal/types"
"golang.org/x/crypto/bcrypt"
)
func FindUser(userList types.UserList, username string) (*types.User) {
for _, user := range userList.Users {
if user.Username == username {
return &user
}
}
return nil
}
func CheckPassword(user types.User, password string) bool {
hashedPasswordErr := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
return hashedPasswordErr == nil
}

View File

@@ -5,6 +5,24 @@ type LoginQuery struct {
}
type LoginRequest struct {
Email string `json:"email"`
Username string `json:"username"`
Password string `json:"password"`
}
type User struct {
Username string
Password string
}
type UserList struct {
Users []User
}
type Config struct {
Port int `validate:"number" mapstructure:"port"`
Address string `mapstructure:"address, ip4_addr"`
Secret string `validate:"required,len=32" mapstructure:"secret"`
RootURL string `validate:"required,url" mapstructure:"root-url"`
AppURL string `validate:"required,url" mapstructure:"app-url"`
Users string `validate:"required" mapstructure:"users"`
}

29
internal/utils/utils.go Normal file
View File

@@ -0,0 +1,29 @@
package utils
import (
"errors"
"strings"
"tinyauth/internal/types"
)
func CreateUsersList(users string) (types.UserList, error) {
var userList types.UserList
userListString := strings.Split(users, ",")
if len(userListString) == 0 {
return types.UserList{}, errors.New("no users found")
}
for _, user := range userListString {
userSplit := strings.Split(user, ":")
if len(userSplit) != 2 {
return types.UserList{}, errors.New("invalid user format")
}
userList.Users = append(userList.Users, types.User{
Username: userSplit[0],
Password: userSplit[1],
})
}
return userList, nil
}