package queryapi
import (
"context"
"fmt"
"net/http"
"strings"
"github.com/labstack/echo/v4"
"github.com/lestrrat-go/jwx/v2/jwt"
)
// Constants for route paths
const (
LOGIN_CALLBACK_PATH = "/login-callback"
)
// endpointsList keeps track of registered endpoints
// This list should be kept in sync with actual route registrations
var endpointsList = []string{
// Auth Service Endpoints
"/login",
LOGIN_CALLBACK_PATH,
"/logout",
"/home",
// Client Service Endpoints
"/client",
// Query API Endpoints
"/query",
// Document Service Endpoints
"/document",
// Export Service Endpoints
"/export",
}
// homeHandler renders a simple HTML page with links to all endpoints
// and displays authentication status based on JWT token
func HomeHandler(c echo.Context) error {
var linksHTML string
baseURL := "http://localhost:8080"
// Create list items for each endpoint
for _, endpoint := range endpointsList {
// Skip endpoints with path parameters for direct linking
if strings.Contains(endpoint, ":") {
displayPath := strings.Replace(endpoint, ":id", "{id}", -1)
linksHTML += fmt.Sprintf("
%s (requires parameter)\n", displayPath)
} else {
linksHTML += fmt.Sprintf("%s\n", baseURL, endpoint, endpoint)
}
}
// Check if user is authenticated by looking for token in cookie
tokenCookie, err := c.Cookie("auth_token")
isAuthenticated := (err == nil && tokenCookie.Value != "")
// Variables for user info
var subject string
// If authenticated, try to decode the JWT token to get user info
if isAuthenticated {
// Use the same JWT parsing logic as the middleware to handle formatted tokens
tokenString := tokenCookie.Value
// Handle RFC-compliant unsecured JWTs that may have only 2 parts (header.payload.)
parts := strings.Split(tokenString, ".")
if len(parts) == 2 {
// Add empty signature part to make it parseable by the JWT library
tokenString = tokenString + "."
}
// Parse token without verification (just for display purposes)
token, err := jwt.Parse(
[]byte(tokenString),
jwt.WithVerify(false), // Skip signature verification
jwt.WithValidate(false), // Skip expiration and other validations
)
if err != nil {
subject = "JWT parsing failed: " + err.Error()
} else if token != nil {
claims, err := token.AsMap(context.Background())
if err != nil {
subject = "Claims extraction failed: " + err.Error()
} else {
if sub, ok := claims["sub"].(string); ok {
subject = sub
} else {
subject = "Subject claim not found or invalid type"
}
}
} else {
subject = "Token is nil"
}
}
// Create authentication status section
var authStatusHTML string
if isAuthenticated {
authStatusHTML = fmt.Sprintf(`
Authentication Status: Authenticated
Subject: %s
Logout
`, subject)
} else {
authStatusHTML = `
Authentication Status: Not Authenticated
You are not currently logged in.
Login
`
}
// Create the complete HTML page
html := fmt.Sprintf(`
Doczy Home
Doczy Home
%s
Available Endpoints
Note: This is a debugging page. Some endpoints require authentication or specific permissions.
`, authStatusHTML, linksHTML)
return c.HTML(http.StatusOK, html)
}