mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-28 04:35:40 +00:00
refactor: split app context and user context (#48)
* refactor: split app context and user context * tests: fix api tests * chore: rename dockerfiles * fix: use correct forwardauth address
This commit is contained in:
@@ -372,7 +372,7 @@ func (api *API) SetupRoutes() {
|
||||
|
||||
api.Router.POST("/api/totp", func(c *gin.Context) {
|
||||
// Create totp struct
|
||||
var totpReq types.Totp
|
||||
var totpReq types.TotpRequest
|
||||
|
||||
// Bind JSON
|
||||
err := c.BindJSON(&totpReq)
|
||||
@@ -461,11 +461,8 @@ func (api *API) SetupRoutes() {
|
||||
})
|
||||
})
|
||||
|
||||
api.Router.GET("/api/status", func(c *gin.Context) {
|
||||
log.Debug().Msg("Checking status")
|
||||
|
||||
// Get user context
|
||||
userContext := api.Hooks.UseUserContext(c)
|
||||
api.Router.GET("/api/app", func(c *gin.Context) {
|
||||
log.Debug().Msg("Getting app context")
|
||||
|
||||
// Get configured providers
|
||||
configuredProviders := api.Providers.GetConfiguredProviders()
|
||||
@@ -475,33 +472,48 @@ func (api *API) SetupRoutes() {
|
||||
configuredProviders = append(configuredProviders, "username")
|
||||
}
|
||||
|
||||
// Fill status struct with data from user context and api config
|
||||
status := types.Status{
|
||||
Username: userContext.Username,
|
||||
IsLoggedIn: userContext.IsLoggedIn,
|
||||
Oauth: userContext.OAuth,
|
||||
Provider: userContext.Provider,
|
||||
// Create app context struct
|
||||
appContext := types.AppContext{
|
||||
Status: 200,
|
||||
Message: "Ok",
|
||||
ConfiguredProviders: configuredProviders,
|
||||
DisableContinue: api.Config.DisableContinue,
|
||||
Title: api.Config.Title,
|
||||
GenericName: api.Config.GenericName,
|
||||
TotpPending: userContext.TotpPending,
|
||||
}
|
||||
|
||||
// Return app context
|
||||
c.JSON(200, appContext)
|
||||
})
|
||||
|
||||
api.Router.GET("/api/user", func(c *gin.Context) {
|
||||
log.Debug().Msg("Getting user context")
|
||||
|
||||
// Get user context
|
||||
userContext := api.Hooks.UseUserContext(c)
|
||||
|
||||
// Create user context response
|
||||
userContextResponse := types.UserContextResponse{
|
||||
Status: 200,
|
||||
IsLoggedIn: userContext.IsLoggedIn,
|
||||
Username: userContext.Username,
|
||||
Provider: userContext.Provider,
|
||||
Oauth: userContext.OAuth,
|
||||
TotpPending: userContext.TotpPending,
|
||||
}
|
||||
|
||||
// If we are not logged in we set the status to 401 and add the WWW-Authenticate header else we set it to 200
|
||||
if !userContext.IsLoggedIn {
|
||||
log.Debug().Msg("Unauthorized")
|
||||
c.Header("WWW-Authenticate", "Basic realm=\"tinyauth\"")
|
||||
status.Status = 401
|
||||
status.Message = "Unauthorized"
|
||||
userContextResponse.Message = "Unauthorized"
|
||||
} else {
|
||||
log.Debug().Interface("userContext", userContext).Strs("configuredProviders", configuredProviders).Bool("disableContinue", api.Config.DisableContinue).Msg("Authenticated")
|
||||
status.Status = 200
|
||||
status.Message = "Authenticated"
|
||||
log.Debug().Interface("userContext", userContext).Msg("Authenticated")
|
||||
userContextResponse.Message = "Authenticated"
|
||||
}
|
||||
|
||||
// Return data
|
||||
c.JSON(200, status)
|
||||
// Return user context
|
||||
c.JSON(200, userContextResponse)
|
||||
})
|
||||
|
||||
api.Router.GET("/api/oauth/url/:provider", func(c *gin.Context) {
|
||||
@@ -710,7 +722,12 @@ func (api *API) Run() {
|
||||
log.Info().Str("address", api.Config.Address).Int("port", api.Config.Port).Msg("Starting server")
|
||||
|
||||
// Run server
|
||||
api.Router.Run(fmt.Sprintf("%s:%d", api.Config.Address, api.Config.Port))
|
||||
err := api.Router.Run(fmt.Sprintf("%s:%d", api.Config.Address, api.Config.Port))
|
||||
|
||||
// Check error
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to start server")
|
||||
}
|
||||
}
|
||||
|
||||
// handleError logs the error and redirects to the error page (only meant for stuff the user may access does not apply for login paths)
|
||||
|
||||
@@ -2,6 +2,7 @@ package api_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -122,9 +123,9 @@ func TestLogin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test status
|
||||
func TestStatus(t *testing.T) {
|
||||
t.Log("Testing status")
|
||||
// Test user context
|
||||
func TestUserContext(t *testing.T) {
|
||||
t.Log("Testing user context")
|
||||
|
||||
// Get API
|
||||
api := getAPI(t)
|
||||
@@ -133,7 +134,7 @@ func TestStatus(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
// Create request
|
||||
req, err := http.NewRequest("GET", "/api/status", nil)
|
||||
req, err := http.NewRequest("GET", "/api/user", nil)
|
||||
|
||||
// Check if there was an error
|
||||
if err != nil {
|
||||
@@ -152,11 +153,31 @@ func TestStatus(t *testing.T) {
|
||||
// Assert
|
||||
assert.Equal(t, recorder.Code, http.StatusOK)
|
||||
|
||||
// Parse the body
|
||||
body := recorder.Body.String()
|
||||
// Read the body of the response
|
||||
body, bodyErr := io.ReadAll(recorder.Body)
|
||||
|
||||
if !strings.Contains(body, "user") {
|
||||
t.Fatalf("Expected user in body")
|
||||
// Check if there was an error
|
||||
if bodyErr != nil {
|
||||
t.Fatalf("Error getting body: %v", bodyErr)
|
||||
}
|
||||
|
||||
// Unmarshal the body into the user struct
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
var user User
|
||||
|
||||
jsonErr := json.Unmarshal(body, &user)
|
||||
|
||||
// Check if there was an error
|
||||
if jsonErr != nil {
|
||||
t.Fatalf("Error unmarshalling body: %v", jsonErr)
|
||||
}
|
||||
|
||||
// We should get the username back
|
||||
if user.Username != "user" {
|
||||
t.Fatalf("Expected user, got %s", user.Username)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ type Config struct {
|
||||
SessionExpiry int `mapstructure:"session-expiry"`
|
||||
LogLevel int8 `mapstructure:"log-level" validate:"min=-1,max=5"`
|
||||
Title string `mapstructure:"app-title"`
|
||||
EnvFile string `mapstructure:"env-file"`
|
||||
}
|
||||
|
||||
// UserContext is the context for the user
|
||||
@@ -138,22 +139,28 @@ type Proxy struct {
|
||||
Proxy string `uri:"proxy" binding:"required"`
|
||||
}
|
||||
|
||||
// Status response
|
||||
type Status struct {
|
||||
// User Context response is the response for the user context endpoint
|
||||
type UserContextResponse struct {
|
||||
Status int `json:"status"`
|
||||
Message string `json:"message"`
|
||||
IsLoggedIn bool `json:"isLoggedIn"`
|
||||
Username string `json:"username"`
|
||||
Provider string `json:"provider"`
|
||||
Oauth bool `json:"oauth"`
|
||||
TotpPending bool `json:"totpPending"`
|
||||
}
|
||||
|
||||
// App Context is the response for the app context endpoint
|
||||
type AppContext struct {
|
||||
Status int `json:"status"`
|
||||
Message string `json:"message"`
|
||||
IsLoggedIn bool `json:"isLoggedIn"`
|
||||
Username string `json:"username"`
|
||||
Provider string `json:"provider"`
|
||||
Oauth bool `json:"oauth"`
|
||||
ConfiguredProviders []string `json:"configuredProviders"`
|
||||
DisableContinue bool `json:"disableContinue"`
|
||||
Title string `json:"title"`
|
||||
GenericName string `json:"genericName"`
|
||||
TotpPending bool `json:"totpPending"`
|
||||
}
|
||||
|
||||
// Totp request
|
||||
type Totp struct {
|
||||
// Totp request is the request for the totp endpoint
|
||||
type TotpRequest struct {
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user