258 lines
7.4 KiB
Go
258 lines
7.4 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"image/png"
|
|
"log"
|
|
"path"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
"github.com/pquerna/otp/totp"
|
|
"golang.org/x/crypto/scrypt"
|
|
"nim.jasinco.work/app/internal"
|
|
"nim.jasinco.work/app/nimdb"
|
|
)
|
|
|
|
type NewAdmin struct {
|
|
Name string `json:"name"`
|
|
Password string `json:"password"`
|
|
TOTP_Secret string `json:"totp_secret"`
|
|
}
|
|
type AdminAuth struct {
|
|
Name string `json:"name"`
|
|
Password string `json:"password"`
|
|
TOTP_code string `json:"totp_code"`
|
|
}
|
|
|
|
func Admin_create(c *fiber.Ctx) error {
|
|
cfg := new(NewAdmin)
|
|
if err := c.BodyParser(cfg); err != nil {
|
|
return fiber.ErrBadRequest
|
|
}
|
|
|
|
hashed, err := scrypt.Key([]byte(cfg.Password), []byte(internal.SALT), 32768, 8, 1, 32)
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
err = internal.NIMDB.AdminCreateAccount(c.Context(), nimdb.AdminCreateAccountParams{Username: cfg.Name, Password: base64.StdEncoding.EncodeToString(hashed), Totp: cfg.TOTP_Secret})
|
|
if err != nil {
|
|
log.Println(base64.StdEncoding.EncodeToString(hashed), err)
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
return c.SendStatus(fiber.StatusCreated)
|
|
}
|
|
|
|
func Admin_new_totp_code(c *fiber.Ctx) error {
|
|
name := c.Query("name")
|
|
if len(name) == 0 {
|
|
return fiber.ErrBadRequest
|
|
}
|
|
key, err := totp.Generate(totp.GenerateOpts{Issuer: "TCIVS_NIMING", AccountName: name})
|
|
if err != nil {
|
|
return fiber.ErrInternalServerError
|
|
}
|
|
var buf bytes.Buffer
|
|
img, err := key.Image(200, 200)
|
|
png.Encode(&buf, img)
|
|
return c.JSON(fiber.Map{"key": key.Secret(), "img": base64.StdEncoding.EncodeToString(buf.Bytes())})
|
|
}
|
|
|
|
func Admin_Login(c *fiber.Ctx) error {
|
|
cred := new(AdminAuth)
|
|
|
|
if err := c.BodyParser(cred); err != nil {
|
|
return fiber.ErrBadRequest
|
|
}
|
|
hashed, err := scrypt.Key([]byte(cred.Password), []byte(internal.SALT), 32768, 8, 1, 32)
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
rec, err := internal.NIMDB.AdminLoginGetTOTP(c.Context(), nimdb.AdminLoginGetTOTPParams{Username: cred.Name, Password: base64.StdEncoding.EncodeToString(hashed)})
|
|
|
|
if err != nil {
|
|
log.Println(err)
|
|
return c.SendStatus(fiber.StatusUnauthorized)
|
|
}
|
|
if !totp.Validate(cred.TOTP_code, rec.Totp) {
|
|
log.Println(totp.GenerateCode(rec.Totp, time.Now()))
|
|
return c.SendStatus(fiber.StatusUnauthorized)
|
|
}
|
|
|
|
claims := jwt.MapClaims{"name": cred.Name, "admin": rec.Super}
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
|
|
t, err := token.SignedString([]byte(internal.JWT_SECRET))
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
cookie := new(fiber.Cookie)
|
|
cookie.Name = "token"
|
|
cookie.Value = t
|
|
cookie.Expires = time.Now().Add(5 * time.Hour)
|
|
c.Cookie(cookie)
|
|
return c.JSON(fiber.Map{"token": t})
|
|
}
|
|
|
|
func Admin_Fetch_Post(c *fiber.Ctx) error {
|
|
user := c.Locals("user").(*jwt.Token)
|
|
claims := user.Claims.(jwt.MapClaims)
|
|
super := claims["admin"].(bool)
|
|
ctx := c.Context()
|
|
if !super {
|
|
rec, err := internal.NIMDB.AdminGetPost(ctx)
|
|
if err != nil {
|
|
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
type recwithimg struct {
|
|
Id int32 `json:"id"`
|
|
Content string `json:"content"`
|
|
Signing pgtype.Text `json:"signing"`
|
|
Post_at time.Time `json:"post_at"`
|
|
Enclosue []string `json:"enclosure"`
|
|
}
|
|
rec_with_img := make([]recwithimg, len(rec))
|
|
for id, k := range rec {
|
|
rec_with_img[id] = recwithimg{Id: k.ID, Content: k.Content, Signing: k.Signing, Post_at: k.PostAt.Time}
|
|
imgrec, err := internal.NIMDB.AdminGetMedia(ctx, pgtype.Int4{Int32: k.ID, Valid: true})
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
rec_with_img[id].Enclosue = imgrec
|
|
}
|
|
return c.JSON(rec_with_img)
|
|
} else {
|
|
|
|
rec, err := internal.NIMDB.SuperAdminGetPost(ctx)
|
|
if err != nil {
|
|
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
type recwithimg struct {
|
|
Id int32 `json:"id"`
|
|
Content string `json:"content"`
|
|
Signing pgtype.Text `json:"signing"`
|
|
Post_at time.Time `json:"post_at"`
|
|
Enclosue []string `json:"enclosure"`
|
|
Phase nimdb.PostPhase `json:"phase"`
|
|
}
|
|
rec_with_img := make([]recwithimg, len(rec))
|
|
for id, k := range rec {
|
|
rec_with_img[id] = recwithimg{Id: k.ID, Content: k.Content, Signing: k.Signing, Post_at: k.PostAt.Time, Phase: k.Phase}
|
|
imgrec, err := internal.NIMDB.AdminGetMedia(ctx, pgtype.Int4{Int32: k.ID, Valid: true})
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
rec_with_img[id].Enclosue = imgrec
|
|
}
|
|
return c.JSON(rec_with_img)
|
|
}
|
|
|
|
}
|
|
|
|
type Verify struct {
|
|
Id int32 `json:"post"`
|
|
Check bool `json:"check"`
|
|
}
|
|
type VerifyList struct {
|
|
Choice []Verify `json:"choice"`
|
|
}
|
|
|
|
func AdminVerify(c *fiber.Ctx) error {
|
|
user := c.Locals("user").(*jwt.Token)
|
|
claims := user.Claims.(jwt.MapClaims)
|
|
super := claims["admin"].(bool)
|
|
ctx := c.Context()
|
|
tx, err := internal.POOL.Begin(ctx)
|
|
defer tx.Rollback(ctx)
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
qtx := internal.NIMDB.WithTx(tx)
|
|
post_verify_list := new(VerifyList)
|
|
log.Println(string(c.Body()))
|
|
if err = c.BodyParser(post_verify_list); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
if !super {
|
|
for _, post_verify := range post_verify_list.Choice {
|
|
if post_verify.Check {
|
|
_, err = qtx.AdminVerify(ctx, nimdb.AdminVerifyParams{ID: post_verify.Id, Phase: nimdb.PostPhaseOk})
|
|
if err != nil {
|
|
log.Println(err.Error(), post_verify.Id)
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
err = qtx.AdminUpdateImage(ctx, pgtype.Int4{Int32: post_verify.Id, Valid: true})
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
if internal.IGAPI_ACTIVATE {
|
|
internal.IGAPI_CHAN <- internal.PR{ACT_TYPE: 0, ID: post_verify.Id}
|
|
}
|
|
|
|
} else {
|
|
_, err = qtx.AdminVerify(ctx, nimdb.AdminVerifyParams{ID: post_verify.Id, Phase: nimdb.PostPhaseRejected})
|
|
if err != nil {
|
|
log.Println(err.Error())
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
for _, post_verify := range post_verify_list.Choice {
|
|
if post_verify.Check {
|
|
_, err = qtx.SuperAdminVerify(ctx, nimdb.SuperAdminVerifyParams{ID: post_verify.Id, Phase: nimdb.PostPhaseOk})
|
|
if err != nil {
|
|
log.Println(err.Error(), post_verify.Id)
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
err = qtx.AdminUpdateImage(ctx, pgtype.Int4{Int32: post_verify.Id, Valid: true})
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
|
|
}
|
|
if internal.IGAPI_ACTIVATE {
|
|
internal.IGAPI_CHAN <- internal.PR{ACT_TYPE: 0, ID: post_verify.Id}
|
|
}
|
|
|
|
} else {
|
|
_, err = qtx.SuperAdminVerify(ctx, nimdb.SuperAdminVerifyParams{ID: post_verify.Id, Phase: nimdb.PostPhaseAdminRejected})
|
|
if err != nil {
|
|
log.Println(err.Error())
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return tx.Commit(ctx)
|
|
}
|
|
|
|
const adminpage_basepath = "./admin_panel/dist"
|
|
|
|
func AdminSendPage(c *fiber.Ctx) error {
|
|
pagepath := c.Params("*")
|
|
if pagepath == "login" || pagepath == "panel" || pagepath == "new_account" {
|
|
err := c.SendFile(path.Join(adminpage_basepath, "index.html"))
|
|
if err != nil {
|
|
log.Println(err)
|
|
return c.SendStatus(fiber.StatusNotFound)
|
|
}
|
|
return nil
|
|
}
|
|
err := c.SendFile(path.Join(adminpage_basepath, pagepath))
|
|
if err != nil {
|
|
c.SendStatus(404)
|
|
}
|
|
return nil
|
|
}
|