223 lines
6.1 KiB
Go
223 lines
6.1 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"git.ctdo.de/ctdo/machinelock-manager/config"
|
|
"git.ctdo.de/ctdo/machinelock-manager/cookies"
|
|
"git.ctdo.de/ctdo/machinelock-manager/db"
|
|
"git.ctdo.de/ctdo/machinelock-manager/oidc"
|
|
"git.ctdo.de/ctdo/machinelock-manager/templates"
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func main() {
|
|
router := gin.New()
|
|
cookies.Init(router)
|
|
authGrp := router.Group("/")
|
|
authGrp.Use(cookies.CheckAuth)
|
|
{
|
|
authGrp.GET("/", index) // overview machine / token connection
|
|
authGrp.GET("/machines", machines) // machine listing
|
|
authGrp.POST("/tokens", createToken) // create a new rfid token
|
|
authGrp.POST("/machines", createMachine) // create a new machine
|
|
authGrp.POST("/tokens/:id", editToken) // edit a token (only nick and allowed machines)
|
|
authGrp.POST("/machines/:id", editMachine) // edit a machine
|
|
authGrp.GET("/machines/:id/delete", deleteMachine) // deletes a machine
|
|
authGrp.GET("/tokens/:id/delete", deleteToken) // deletes a token
|
|
|
|
}
|
|
router.GET("/bootstrap.min.css", bs) // static bootstrap file serving
|
|
router.GET("/auth", oidc.HandleRedirect) // oidc redirect handler
|
|
router.GET("/auth/success", oidc.HandleOauthCallback) // oauth flow callback
|
|
router.GET("/machine/:slug", GetMachine) // machine api to get allowed tokens
|
|
router.GET("/logout", logout)
|
|
router.GET("/forbidden", forbidden)
|
|
router.Run("[::]:" + strconv.Itoa(config.Port))
|
|
}
|
|
|
|
func forbidden(c *gin.Context) {
|
|
templates.Templates.ExecuteTemplate(c.Writer, "forbidden", gin.H{})
|
|
}
|
|
|
|
func logout(c *gin.Context) {
|
|
cookies.Logout(c)
|
|
c.Redirect(http.StatusFound, "/")
|
|
}
|
|
|
|
func bs(c *gin.Context) {
|
|
c.FileFromFS("templates/bootstrap.min.css", http.FS(templates.Res))
|
|
}
|
|
|
|
func returnInternalError(c *gin.Context, err error) {
|
|
slog.Error("an error occured", "error", err)
|
|
c.String(http.StatusInternalServerError, "text", "Internal Error")
|
|
}
|
|
|
|
func index(c *gin.Context) {
|
|
var tokens []db.Token
|
|
if err := db.DB.Preload("Machines").Find(&tokens).Error; err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
var machines []db.Machine
|
|
if err := db.DB.Find(&machines).Error; err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
templates.Templates.ExecuteTemplate(c.Writer, "index", gin.H{
|
|
"Tokens": tokens,
|
|
"Machines": machines,
|
|
})
|
|
}
|
|
|
|
func machines(c *gin.Context) {
|
|
var machines []db.Machine
|
|
if err := db.DB.Find(&machines).Error; err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
templates.Templates.ExecuteTemplate(c.Writer, "machines", machines)
|
|
}
|
|
func createMachine(c *gin.Context) {
|
|
var form db.Machine
|
|
if err := c.ShouldBind(&form); err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
machine := db.Machine{
|
|
Name: form.Name,
|
|
Slug: form.Slug,
|
|
}
|
|
if err := db.DB.Create(&machine).Error; err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
c.Redirect(http.StatusFound, "/machines")
|
|
}
|
|
func editMachine(c *gin.Context) {
|
|
var machine db.Machine
|
|
if err := db.DB.Where("id = ?", c.Param("id")).First(&machine).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.String(http.StatusNotFound, "gibts nich")
|
|
return
|
|
}
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
var form db.Machine
|
|
if err := c.ShouldBind(&form); err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
machine.Name = form.Name
|
|
machine.Slug = form.Slug
|
|
db.DB.Save(&machine)
|
|
c.Redirect(http.StatusFound, "/machines")
|
|
}
|
|
func deleteMachine(c *gin.Context) {
|
|
if err := db.DB.Where("id = ?", c.Param("id")).Delete(db.Machine{}).Error; err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
c.Redirect(http.StatusFound, "/machines")
|
|
}
|
|
func deleteToken(c *gin.Context) {
|
|
if err := db.DB.Where("id = ?", c.Param("id")).Delete(db.Token{}).Error; err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
c.Redirect(http.StatusFound, "/")
|
|
}
|
|
|
|
func createToken(c *gin.Context) {
|
|
var form db.Token
|
|
if err := c.ShouldBind(&form); err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
token := db.Token{
|
|
Nick: form.Nick,
|
|
ID: form.ID,
|
|
}
|
|
if err := db.DB.Create(&token).Error; err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
c.Redirect(http.StatusFound, "/")
|
|
}
|
|
|
|
func editToken(c *gin.Context) {
|
|
var token db.Token
|
|
if err := db.DB.Where("id = ?", c.Param("id")).First(&token).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.String(http.StatusNotFound, "gibts nich")
|
|
return
|
|
}
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
var form struct {
|
|
Nick string `form:"nick"`
|
|
Machine map[string]string `form:"machine"`
|
|
}
|
|
if err := c.ShouldBind(&form); err != nil {
|
|
returnInternalError(c, err)
|
|
return
|
|
}
|
|
form.Machine = c.PostFormMap("machine")
|
|
db.DB.Model(&token).Association("Machines").Clear()
|
|
token.Nick = form.Nick
|
|
token.Machines = make([]*db.Machine, 0)
|
|
for id := range form.Machine {
|
|
var m db.Machine
|
|
if err := db.DB.Where("id = ?", id).First(&m).Error; err == nil {
|
|
token.Machines = append(token.Machines, &m)
|
|
} else {
|
|
slog.Error(err.Error())
|
|
}
|
|
}
|
|
if err := db.DB.Omit("Machines.*").Save(&token).Error; err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
c.Redirect(http.StatusFound, "/")
|
|
}
|
|
|
|
func GetMachine(c *gin.Context) {
|
|
if config.MachineToken == "" {
|
|
c.JSON(http.StatusServiceUnavailable, gin.H{
|
|
"error": "no machine auth token is set, skipping response for security reasons",
|
|
})
|
|
return
|
|
}
|
|
if c.Request.Header.Get("Authorization") == fmt.Sprintf("Bearer %s", config.MachineToken) {
|
|
var machine db.Machine
|
|
if err := db.DB.Where("slug = ?", c.Param("slug")).Preload("Tokens").First(&machine).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"error": "not found",
|
|
})
|
|
return
|
|
}
|
|
slog.Error(err.Error())
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"error": "internal error",
|
|
})
|
|
return
|
|
}
|
|
allowedTokens := make([]string, 0)
|
|
for _, t := range machine.Tokens {
|
|
allowedTokens = append(allowedTokens, t.ID)
|
|
}
|
|
c.JSON(http.StatusOK, allowedTokens)
|
|
} else {
|
|
c.JSON(http.StatusUnauthorized, gin.H{
|
|
"error": "unauthorized",
|
|
})
|
|
}
|
|
}
|