72 lines
1.4 KiB
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()
|
|
}
|