mirror of
https://github.com/pommee/goaway.git
synced 2026-05-06 08:40:41 -05:00
173 lines
4.5 KiB
Go
173 lines
4.5 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"goaway/backend/alert"
|
|
"goaway/backend/audit"
|
|
"goaway/backend/user"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func (api *API) registerAuthRoutes() {
|
|
api.router.POST("/api/login", api.handleLogin)
|
|
api.router.GET("/api/authentication", api.getAuthentication)
|
|
api.routes.PUT("/password", api.updatePassword)
|
|
|
|
api.routes.POST("/apiKey", api.createAPIKey)
|
|
api.routes.GET("/apiKey", api.getAPIKeys)
|
|
api.routes.GET("/deleteApiKey", api.deleteAPIKey)
|
|
}
|
|
|
|
func (api *API) handleLogin(c *gin.Context) {
|
|
allowed, timeUntilReset := api.RateLimiter.CheckLimit(c.ClientIP())
|
|
if !allowed {
|
|
c.JSON(http.StatusTooManyRequests, gin.H{
|
|
"error": "Too many login attempts. Please try again later.",
|
|
"retryAfterSeconds": timeUntilReset,
|
|
})
|
|
return
|
|
}
|
|
|
|
var loginUser user.User
|
|
if err := c.BindJSON(&loginUser); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"})
|
|
return
|
|
}
|
|
|
|
if err := api.UserService.ValidateCredentials(loginUser); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
|
|
return
|
|
}
|
|
|
|
if api.UserService.Authenticate(loginUser.Username, loginUser.Password) {
|
|
token, err := generateToken(loginUser.Username, api.Config.API.JWTSecret)
|
|
if err != nil {
|
|
log.Info("Token generation failed for user %s: %v", loginUser.Username, err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": "Authentication service temporarily unavailable",
|
|
})
|
|
return
|
|
}
|
|
|
|
c.Header("Access-Control-Allow-Origin", "*")
|
|
c.Header("Access-Control-Allow-Credentials", "true")
|
|
|
|
setAuthCookie(c.Writer, token)
|
|
c.JSON(http.StatusOK, gin.H{"message": "Login successful"})
|
|
} else {
|
|
c.JSON(http.StatusUnauthorized, gin.H{
|
|
"error": "Invalid username or password",
|
|
})
|
|
}
|
|
}
|
|
|
|
func (api *API) getAuthentication(c *gin.Context) {
|
|
c.JSON(http.StatusOK, gin.H{"enabled": api.Authentication})
|
|
}
|
|
|
|
func (api *API) updatePassword(c *gin.Context) {
|
|
type passwordChange struct {
|
|
CurrentPassword string `json:"currentPassword"`
|
|
NewPassword string `json:"newPassword"`
|
|
}
|
|
|
|
var newCredentials passwordChange
|
|
if err := c.BindJSON(&newCredentials); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"})
|
|
return
|
|
}
|
|
|
|
if !api.UserService.Authenticate("admin", newCredentials.CurrentPassword) {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Current password is not valid"})
|
|
return
|
|
}
|
|
|
|
if err := api.UserService.UpdatePassword("admin", newCredentials.NewPassword); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Unable to update password"})
|
|
return
|
|
}
|
|
|
|
logMsg := "Password changed for user 'admin'"
|
|
api.DNSServer.AuditService.CreateAudit(&audit.Entry{
|
|
Topic: audit.TopicUser,
|
|
Message: logMsg,
|
|
})
|
|
go func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
_ = api.DNSServer.AlertService.SendToAll(ctx, alert.Message{
|
|
Title: "System",
|
|
Content: logMsg,
|
|
Severity: SeverityWarning,
|
|
})
|
|
}()
|
|
|
|
log.Warning("%s", logMsg)
|
|
c.Status(http.StatusOK)
|
|
}
|
|
|
|
func (api *API) createAPIKey(c *gin.Context) {
|
|
type NewAPIKeyName struct {
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
body, err := io.ReadAll(c.Request.Body)
|
|
if err != nil {
|
|
log.Error("Failed to read request body: %v", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
|
|
return
|
|
}
|
|
|
|
var request NewAPIKeyName
|
|
if err := json.Unmarshal(body, &request); err != nil {
|
|
log.Error("Failed to parse JSON: %v", err)
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON format"})
|
|
return
|
|
}
|
|
|
|
apiKey, err := api.KeyService.CreateKey(request.Name)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
go func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
_ = api.DNSServer.AlertService.SendToAll(ctx, alert.Message{
|
|
Title: "System",
|
|
Content: fmt.Sprintf("New API key created with the name '%s'", request.Name),
|
|
Severity: SeverityWarning,
|
|
})
|
|
}()
|
|
|
|
c.JSON(http.StatusOK, apiKey)
|
|
}
|
|
|
|
func (api *API) getAPIKeys(c *gin.Context) {
|
|
apiKeys, err := api.KeyService.GetAllKeys()
|
|
if err != nil {
|
|
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, apiKeys)
|
|
}
|
|
|
|
func (api *API) deleteAPIKey(c *gin.Context) {
|
|
keyName := c.Query("name")
|
|
|
|
err := api.KeyService.DeleteKey(keyName)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Deleted api key!"})
|
|
}
|