71 lines
1.7 KiB
Go
71 lines
1.7 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// configureWebUI adds an optional SPA fallback to the existing GoAdmin Gin
|
|
// engine. API and framework routes keep their normal handlers; the fallback is
|
|
// enabled only for Windows delivery packages that set SENSE_WEB_ROOT.
|
|
func configureWebUI(r *gin.Engine) {
|
|
root := strings.TrimSpace(os.Getenv("SENSE_WEB_ROOT"))
|
|
if root == "" {
|
|
return
|
|
}
|
|
absRoot, err := filepath.Abs(root)
|
|
if err != nil {
|
|
return
|
|
}
|
|
index := filepath.Join(absRoot, "index.html")
|
|
if info, statErr := os.Stat(index); statErr != nil || info.IsDir() {
|
|
return
|
|
}
|
|
|
|
r.NoRoute(func(c *gin.Context) {
|
|
if c.Request.Method != http.MethodGet && c.Request.Method != http.MethodHead {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
if isBackendPath(c.Request.URL.Path) {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
requested := filepath.Clean(filepath.FromSlash(strings.TrimPrefix(c.Request.URL.Path, "/")))
|
|
if requested == "." {
|
|
requested = ""
|
|
}
|
|
candidate := filepath.Join(absRoot, requested)
|
|
if withinRoot(absRoot, candidate) {
|
|
if info, statErr := os.Stat(candidate); statErr == nil && !info.IsDir() {
|
|
c.File(candidate)
|
|
return
|
|
}
|
|
}
|
|
if filepath.Ext(requested) != "" {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
c.File(index)
|
|
})
|
|
}
|
|
|
|
func withinRoot(root, candidate string) bool {
|
|
rel, err := filepath.Rel(root, candidate)
|
|
return err == nil && rel != ".." && !strings.HasPrefix(rel, ".."+string(filepath.Separator))
|
|
}
|
|
|
|
func isBackendPath(path string) bool {
|
|
for _, prefix := range []string{"/api/", "/swagger/", "/static/", "/form-generator/"} {
|
|
if strings.HasPrefix(path, prefix) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|