zkt24/z1/backend/server.go
2024-04-25 13:51:47 +02:00

233 lines
5.4 KiB
Go

package main
import (
"bytes"
"fmt"
"log"
"encoding/base64"
"encoding/gob"
"encoding/json"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
jwtware "github.com/gofiber/jwt/v3"
"github.com/golang-jwt/jwt/v4"
)
type Creds struct {
Username string `json:"username" xml:"username" form:"username"`
Pass string `json:"pass" xml:"pass" form:"pass"`
}
type Response struct {
Status string `json:"status"`
Text string `json:"text"`
}
type JsonComment struct {
Array []Comment
}
// go binary encoder
func ToGOB64(m JsonComment) string {
b := bytes.Buffer{}
e := gob.NewEncoder(&b)
err := e.Encode(m)
if err != nil {
fmt.Println(`failed gob Encode`, err)
}
return base64.StdEncoding.EncodeToString(b.Bytes())
}
// go binary decoder
func FromGOB64(str string) JsonComment {
m := JsonComment{}
by, err := base64.StdEncoding.DecodeString(str)
if err != nil {
fmt.Println(`failed base64 Decode`, err)
}
b := bytes.Buffer{}
b.Write(by)
d := gob.NewDecoder(&b)
err = d.Decode(&m)
if err != nil {
fmt.Println(`failed gob Decode`, err)
}
return m
}
func malformedToken(c *fiber.Ctx, w error) error {
res := Response{Status: "bad", Text: "Malformed token"}
return c.JSON(res)
}
func main() {
app := fiber.New()
db := initDB()
bad := Response{Status: "bad", Text: "Unauthorized"}
errResponse := Response{Status: "bad", Text: "Woops something went wrong ¯\\_(ツ)_/¯"}
app.Use(cors.New(cors.Config{
AllowOrigins: "*",
AllowHeaders: "Origin, Content-Type, Accept, Authorization",
}))
app.Post("/login", func(c *fiber.Ctx) error {
p := new(Creds)
if err := c.BodyParser(p); err != nil {
return err
}
var res User
if err := db.First(&res, "Username = ?", p.Username).Error; err != nil {
return c.JSON(bad)
}
if !CheckPasswordHash(p.Pass, res.Password) {
return c.JSON(bad)
}
token, _ := Sign(p.Username)
response := Response{Status: "ok", Text: token}
return c.JSON(response)
})
app.Post("/signup", func(c *fiber.Ctx) error {
details := new(User)
if err := c.BodyParser(details); err != nil {
return err
}
if !validateUser(*details) {
return c.JSON(errResponse)
}
details.Active = true
var query User
if err := db.First(&query, "Username = ?", details.Username).Error; err != nil && query.Username != "" {
return c.JSON(errResponse)
}
hashedPass, err := HashPassword(details.Password)
if err != nil {
return c.JSON(errResponse)
}
details.Password = hashedPass
db.Create(details)
newUser := Response{Status: "ok", Text: "user created successfully"}
return c.JSON(newUser)
})
app.Use(jwtware.New(jwtware.Config{
SigningKey: []byte("ShXYLRYfFOw+upPD"),
ErrorHandler: malformedToken,
}))
app.Get("/posts", func(c *fiber.Ctx) error {
var query []Post
c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSONCharsetUTF8)
db.Find(&query)
res, err := json.Marshal(query)
if err != nil {
return c.JSON(errResponse)
}
return c.SendString(string(res))
})
app.Get("/posts/:uid", func(c *fiber.Ctx) error {
var post Post
db.Select("content").Find(&post, "ID = ?", c.Params("uid"))
res := Response{Status: "ok", Text: post.Content}
return c.JSON(res)
})
app.Get("/profile/:uid", func(c *fiber.Ctx) error {
var user APIUser
if err := db.Model(&User{}).Find(&user, "Username = ?", c.Params("uid")).Error; err != nil {
return c.JSON(errResponse)
}
return c.JSON(user)
})
app.Get("/profile", func(c *fiber.Ctx) error {
var user APIUser
token := c.Locals("user").(*jwt.Token)
claims := token.Claims.(jwt.MapClaims)
name := claims["username"].(string)
if err := db.Model(&User{}).Find(&user, "Username = ?", name).Error; err != nil {
return c.JSON(errResponse)
}
return c.JSON(user)
})
app.Post("/create", func(c *fiber.Ctx) error {
info := new(Post)
if err := c.BodyParser(info); err != nil {
return c.JSON(errResponse)
}
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["username"].(string)
//figure out how to store user id's instead of usernames
/*
var query User
if err := db.First(&query, "Username = ?", name).Error; err != nil && query.Username != "" {
return c.JSON(errResponse)
}
info.Uuid = query.ID
*/
info.Username = name
db.Create(info)
newPost := Response{Status: "ok", Text: "post created successfully"}
return c.JSON(newPost)
})
app.Post("/comment", func(c *fiber.Ctx) error {
var comment Comment
apiComment := new(APIComment)
if err := c.BodyParser(apiComment); err != nil {
return c.JSON(errResponse)
}
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
name := claims["username"].(string)
comment.PostId = apiComment.PostId
comment.Text = apiComment.Text
comment.Commenter = name
var post Post
db.Select("comments").Find(&post, "ID = ?", comment.PostId)
dbComments := FromGOB64(post.Comments)
comments := JsonComment{Array: append([]Comment{comment}, dbComments.Array...)}
store := ToGOB64(comments)
db.Model(&Post{}).Where("ID = ?", comment.PostId).Update("comments", store)
newComment := Response{Status: "ok", Text: "Comment created successfully"}
return c.JSON(newComment)
})
app.Get("/comments/:uid", func(c *fiber.Ctx) error {
var post Post
db.Select("comments").Find(&post, "ID = ?", c.Params("uid"))
comments := FromGOB64(post.Comments)
return c.JSON(comments)
})
log.Fatal(app.Listen(":3000"))
}