299 lines
7.8 KiB
Go

package main
import (
"database/sql"
"encoding/json"
"fmt"
"io/ioutil"
"os"
//"bytes"
"net/http"
"github.com/dgrijalva/jwt-go"
"golang.org/x/crypto/bcrypt"
"github.com/labstack/echo/v4"
"github.com/google/uuid"
"gitlab.computing.dcu.ie/murphg62/2023-ca400-murphg62-byrnm257/src/backend/pkg/database"
"gitlab.computing.dcu.ie/murphg62/2023-ca400-murphg62-byrnm257/src/backend/pkg/docker"
_ "golang.org/x/mod/module"
)
const (
port = 5432
)
var db, err = database.ConnectDB(os.Getenv("db"), port, os.Getenv("db_user"), os.Getenv("db_pass"), os.Getenv("db_name"))
var jwtSecret = []byte("fAHr+Hlho9qhCePEuMxLVG2i/1tiEqtocAWkcYRJx0s=")
type Schema struct {
Name string `json:"Name"`
Type int `json:"Type"`
}
type Module struct {
Name string `json:"Name"`
Container string `json:"Container"`
}
type User struct {
Username string `json:"Username"`
Password string `json:"Password"`
}
func homePage(c echo.Context) error {
return c.String(http.StatusOK, "Welcome to the home page!")
}
func getSchema(c echo.Context) error {
key := c.Param("container")
requestURL := fmt.Sprintf("http://%s:8080/schema", key)
resp, err := http.Get(requestURL)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
return c.JSONBlob(resp.StatusCode, body)
}
func getComponent(c echo.Context) error {
container := c.Param("container")
component := c.Param("component")
requestURL := fmt.Sprintf("http://%s:8080/component/%s", container, component)
resp, err := http.Get(requestURL)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
return c.JSONBlob(http.StatusOK, body)
}
func postComponent(c echo.Context) error {
container := c.Param("container")
component := c.Param("component")
requestURL := fmt.Sprintf("http://%s:8080/component/%s", container, component)
resp, err := http.Post(requestURL, "application/json", c.Request().Body)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
return c.JSONBlob(http.StatusOK, body)
}
func GetModules(db *sql.DB) echo.HandlerFunc {
return func(c echo.Context) error {
modules := make([]Module, 0)
rows, err := db.Query("SELECT name, container_name FROM Module")
if err != nil {
fmt.Println("test")
return err
}
defer rows.Close()
for rows.Next() {
var module Module
if err := rows.Scan(&module.Name, &module.Container); err != nil {
return err
}
modules = append(modules, module)
}
return c.JSON(http.StatusOK, modules)
}
}
func getFromModule(c echo.Context) error {
url := c.Param("url")
requestURL := fmt.Sprintf("http://%s", url)
fmt.Println(requestURL)
resp, err := http.Get(requestURL)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
return c.JSONBlob(http.StatusOK, body)
}
func postFromModule(c echo.Context) error {
url := c.Param("url")
requestURL := fmt.Sprintf("http://%s", url)
resp, err := http.Post(requestURL, "application/json", c.Request().Body)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
return c.JSONBlob(http.StatusOK, body)
}
func RegisterUser(db *sql.DB) echo.HandlerFunc {
return func(c echo.Context) error {
user := new(User)
if err := c.Bind(user); err != nil {
return err
}
// Check if user already exists
var count int
if err := db.QueryRow("SELECT COUNT(*) FROM users WHERE name = $1", user.Username).Scan(&count); err != nil {
return err
}
if count > 0 {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Username already in use"})
}
// Hash password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
// Insert new user into database
_, err = db.Exec("INSERT INTO users(name, password) VALUES ($1, $2)", user.Username, string(hashedPassword))
if err != nil {
return err
}
return c.JSON(http.StatusOK, map[string]string{"message": "User created"})
}
}
func LoginUser(db *sql.DB, jwtSecret []byte) echo.HandlerFunc {
return func(c echo.Context) error {
login := new(User)
if err := c.Bind(login); err != nil {
return err
}
// Check if user exists
var user User
if err := db.QueryRow("SELECT name, password FROM users WHERE name = $1", login.Username).Scan(&user.Username, &user.Password); err != nil {
if err == sql.ErrNoRows {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid username or password"})
}
return err
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(login.Password)); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid username or password"})
}
// Generate JWT token
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["name"] = user.Username
tokenString, err := token.SignedString(jwtSecret)
if err != nil {
return err
}
return c.JSON(http.StatusOK, map[string]string{"token": tokenString})
}
}
func LogoutUser() echo.HandlerFunc {
return func(c echo.Context) error {
// Clear JWT token cookie
cookie := &http.Cookie{
Name: "jwt",
Value: "",
HttpOnly: true,
Path: "/",
}
http.SetCookie(c.Response().Writer, cookie)
return c.NoContent(http.StatusOK)
}
}
func CreateModule(c echo.Context) error {
var module docker.Module
if err := c.Bind(&module); err != nil {
panic(err)
}
module.ID = uuid.New().String()
s, _ := json.MarshalIndent(module, "", " ")
fmt.Println(string(s))
mod_id := docker.CreateModule(module)
fmt.Println(mod_id)
stmt, err := db.Prepare(`INSERT INTO Module (name, container_name) VALUES ($1, $2);`)
if err != nil {
panic(err)
}
_, err = stmt.Exec(module.Name, mod_id)
return c.NoContent(http.StatusOK)
}
func main() {
if err != nil {
panic(err)
}
db.Exec(`CREATE TABLE IF NOT EXISTS Module (
name VARCHAR(64),
container_name VARCHAR(64));
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL
)
`)
e := echo.New()
e.GET("/", homePage)
e.GET("/:container/schema", getSchema)
e.GET("/component/:container/:component", getComponent)
e.POST("/component/:container/:component", postComponent)
e.GET("/modules", GetModules(db))
e.POST("/user/register", RegisterUser(db))
e.POST("/user/login", LoginUser(db, jwtSecret))
e.POST("/user/logout", LogoutUser())
e.POST("/create_module", CreateModule)
e.GET("/get/:url", getFromModule)
e.POST("/post/:url", postFromModule)
e.Logger.Fatal(e.Start(":10000"))
defer db.Close()
}