From 4a9667b0fb55ea83fb2f5754668b8cc50f60df82 Mon Sep 17 00:00:00 2001 From: Giacomo Sanchietti Date: Wed, 18 Sep 2024 10:15:51 +0200 Subject: [PATCH] feat(api): add unit-openvpn API Store OpenVPN configuration to be used inside the VPN dashboard --- api/main.go | 1 + api/methods/report.go | 49 ++++++++++++++++++++++++++++++ api/models/report.go | 13 ++++++++ api/storage/report_schema.sql.tmpl | 9 ++++++ 4 files changed, 72 insertions(+) diff --git a/api/main.go b/api/main.go index 0d60955..d37087c 100644 --- a/api/main.go +++ b/api/main.go @@ -148,6 +148,7 @@ func main() { reports.POST("/ovpnrw-connections", methods.UpdateOvpnConnections) reports.POST("/dpi-stats", methods.UpdateDpiStats) reports.POST("/unit-name", methods.SetUnitName) + reports.POST("/unit-openvpnrw", methods.SetUnitOpenVPNRW) } // handle missing endpoint diff --git a/api/methods/report.go b/api/methods/report.go index 165bc50..ded742f 100644 --- a/api/methods/report.go +++ b/api/methods/report.go @@ -66,6 +66,55 @@ func SetUnitName(c *gin.Context) { } } +func SetUnitOpenVPNRW(c *gin.Context) { + var req models.UnitOpenVPNRWRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, structs.Map(response.StatusBadRequest{ + Code: 400, + Message: "Invalid request", + Data: err.Error(), + })) + return + } + + if checkUnitId(c.MustGet("UnitId").(string)) != nil { + c.JSON(http.StatusInternalServerError, structs.Map(response.StatusInternalServerError{ + Message: "Unit not found", + Data: nil, + Code: 404, + })) + return + } + + dbpool, dbctx := storage.ReportInstance() + + // Remove all previous data + _, err := dbpool.Exec(dbctx, "DELETE FROM openvpn_config WHERE uuid = $1", c.MustGet("UnitId").(string)) + if err != nil { + logs.Logs.Println("[ERR][UNITOPENVPNRW] error deleting previous data: " + err.Error()) + c.JSON(http.StatusInternalServerError, structs.Map(response.StatusInternalServerError{ + Code: 500, + Message: "Error deleting previous data", + Data: err.Error(), + })) + return + } + + // insert inside OpenVPN table + for _, server := range req.Data { + _, err := dbpool.Exec(dbctx, "INSERT INTO openvpn_config (uuid, instance, name, device, type) VALUES ($1, $2, $3, $4, $5)", c.MustGet("UnitId").(string), server.Instance, server.Name, server.Device, server.Type) + if err != nil { + logs.Logs.Println("[ERR][UNITOPENVPNRW] error inserting data: " + err.Error()) + c.JSON(http.StatusInternalServerError, structs.Map(response.StatusInternalServerError{ + Code: 500, + Message: "Error inserting data", + Data: err.Error(), + })) + return + } + } +} + func checkUnitId(unitId string) error { if unitId == "" { return errors.New("uuid is empty") diff --git a/api/models/report.go b/api/models/report.go index 7bfd7cd..1739919 100644 --- a/api/models/report.go +++ b/api/models/report.go @@ -84,3 +84,16 @@ type DpiStatsRequest struct { type UnitNameRequest struct { Name string `json:"name" binding:"required"` } + +type OpenVPNConfiguration struct { + Instance string `json:"instance" binding:"required"` + Name string `json:"name" binding:"required"` + Device string `json:"device" binding:"required"` + Type string `json:"type"` // valid values are: rw (for roadwarrior), client (for tunnel client), server (for tunnel server) +} + +type OpenVPNConfigurations []OpenVPNConfiguration + +type UnitOpenVPNRWRequest struct { + Data OpenVPNConfigurations `json:"data" binding:"required"` +} diff --git a/api/storage/report_schema.sql.tmpl b/api/storage/report_schema.sql.tmpl index 20d755a..12cee43 100644 --- a/api/storage/report_schema.sql.tmpl +++ b/api/storage/report_schema.sql.tmpl @@ -15,6 +15,15 @@ CREATE TABLE IF NOT EXISTS units ( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); +CREATE TABLE IF NOT EXISTS openvpn_config ( + uuid UUID NOT NULL references units(uuid), + instance TEXT NOT NULL, + name TEXT, + device TEXT NOT NULL, + type TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + -- General retention policies -- Keep raw data for 30 days