forgejo-tickets/internal/handlers/admin/auth.go

72 lines
1.4 KiB
Go

package admin
import (
"encoding/json"
"fmt"
"net"
"net/http"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
)
type TailscaleAuth struct {
allowedUsers []string
}
type tailscaleWhoisResponse struct {
UserProfile struct {
LoginName string `json:"LoginName"`
} `json:"UserProfile"`
}
func (t *TailscaleAuth) Middleware(c *gin.Context) {
if len(t.allowedUsers) == 0 {
// No allowed users configured - allow all (dev mode)
c.Next()
return
}
remoteAddr := c.Request.RemoteAddr
host, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
host = remoteAddr
}
whoisURL := fmt.Sprintf("http://100.100.100.100/localapi/v0/whois?addr=%s", host)
resp, err := http.Get(whoisURL)
if err != nil {
log.Error().Err(err).Msg("tailscale whois error")
c.String(http.StatusUnauthorized, "Unauthorized")
c.Abort()
return
}
defer resp.Body.Close()
var whois tailscaleWhoisResponse
if err := json.NewDecoder(resp.Body).Decode(&whois); err != nil {
log.Error().Err(err).Msg("tailscale whois decode error")
c.String(http.StatusUnauthorized, "Unauthorized")
c.Abort()
return
}
loginName := whois.UserProfile.LoginName
allowed := false
for _, u := range t.allowedUsers {
if u == loginName {
allowed = true
break
}
}
if !allowed {
log.Error().Msgf("tailscale auth: user %q not in allowed list", loginName)
c.String(http.StatusForbidden, "Forbidden")
c.Abort()
return
}
c.Next()
}