porte/web.go

Summary

Maintainability
A
0 mins
Test Coverage
package main

import (
    "bytes"
    "encoding/json"
    "io/fs"
    "net/http"
    "os"
    "strings"

    "github.com/gin-gonic/gin"
    "github.com/labstack/echo/v4"
    "github.com/sirupsen/logrus"
)

type OpenRequest struct {
    CardID  string `json:"card_id"`
    CardPIN string `json:"card_pin"`
}

func checkRequest(c echo.Context) error {
    conf := GetConfig()
    var req OpenRequest
    if err := c.Bind(&req); err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }

    data, err := json.Marshal(req)
    if err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }

    logrus.Debug("POST /auth/card: ", string(data))
    rdr := bytes.NewReader(data)

    // Http client with X-Local-Token
    client := &http.Client{}
    request, err := http.NewRequest("POST", conf.ApiURL+"/auth/card", rdr)
    if err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }

    request.Header.Add("X-Local-Token", conf.LocalToken)
    request.Header.Add("Content-Type", "application/json")

    // post the same request to API_URL
    r, err := client.Do(request)
    if err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }

    if r.StatusCode != http.StatusOK {
        logrus.Debug("/auth/card returned ", r.StatusCode)
        return c.JSON(400, gin.H{"error": "invalid card"})
    }

    request, err = http.NewRequest("GET", conf.ApiURL+"/account/admin", nil)
    if err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }

    request.Header.Add("X-Local-Token", conf.LocalToken)
    for _, cookie := range r.Cookies() {
        request.AddCookie(cookie)
    }

    r2, err := client.Do(request)
    if err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }

    if r2.StatusCode != http.StatusOK {
        logrus.Debug("/account/admin returned ", r2.StatusCode)
        return c.JSON(400, gin.H{"error": "invalid card"})
    }

    type Resp struct {
        IsAllowed bool `json:"is_allowed"`
    }

    var resp Resp
    if err := json.NewDecoder(r2.Body).Decode(&resp); err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }

    if !resp.IsAllowed {
        return c.JSON(400, gin.H{"error": "invalid card"})
    }
    return nil
}

func sendToACM(c echo.Context, data []byte) error {
    // Write 1 to ttyACM*
    files := os.DirFS("/dev")
    err := fs.WalkDir(files, ".", func(path string, d fs.DirEntry, err error) error {
        if err != nil {
            return err
        }

        if strings.HasPrefix(path, "ttyACM") {
            f, err := os.OpenFile("/dev/"+path, os.O_RDWR, 0755)
            if err != nil {
                return err
            }

            f.Write([]byte(data))
            f.Close()
        }

        return nil
    })
    if err != nil {
        return c.JSON(400, gin.H{"error": err.Error()})
    }
    return nil
}

func routes(e *echo.Echo) {
    e.POST("/porte", func(c echo.Context) error {
        if err := checkRequest(c); err != nil {
            return err
        }

        // Check if context has been closed
        if c.Response().Committed {
            return nil
        }

        return sendToACM(c, []byte("1"))
    })

    e.POST("/caisse", func(c echo.Context) error {
        if err := checkRequest(c); err != nil {
            return err
        }

        // Check if context has been closed
        if c.Response().Committed {
            return nil
        }

        return sendToACM(c, []byte("2"))
    })

    e.POST("/ventilo", func(c echo.Context) error {
        if err := checkRequest(c); err != nil {
            return err
        }

        // Check if context has been closed
        if c.Response().Committed {
            return nil
        }

        return sendToACM(c, []byte("3"))
    })
}