Switch from cookie to Bearer token auth and add CORS support - Semi finished
This commit is contained in:
1
go.mod
1
go.mod
@@ -9,6 +9,7 @@ require (
|
|||||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||||
|
github.com/gin-contrib/cors v1.7.5 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.10.0 // indirect
|
github.com/gin-gonic/gin v1.10.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
2
go.sum
2
go.sum
@@ -13,6 +13,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||||
|
github.com/gin-contrib/cors v1.7.5 h1:cXC9SmofOrRg0w9PigwGlHG3ztswH6bqq4vJVXnvYMk=
|
||||||
|
github.com/gin-contrib/cors v1.7.5/go.mod h1:4q3yi7xBEDDWKapjT2o1V7mScKDDr8k+jZ0fSquGoy0=
|
||||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -38,26 +39,31 @@ func (j *JwtTokenGenerator) GenerateToken(claims map[string]interface{}) (string
|
|||||||
// Gin middleware
|
// Gin middleware
|
||||||
func (j *JwtTokenGenerator) GinMiddleware() gin.HandlerFunc {
|
func (j *JwtTokenGenerator) GinMiddleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
token, err := c.Request.Cookie("token")
|
authHeader := c.GetHeader("Authorization")
|
||||||
if err != nil {
|
if authHeader == "" {
|
||||||
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t, err := jwt.Parse(token.Value, func(t *jwt.Token) (interface{}, error) {
|
|
||||||
|
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
|
||||||
|
t, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
|
||||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, jwt.ErrSignatureInvalid
|
return nil, jwt.ErrSignatureInvalid
|
||||||
}
|
}
|
||||||
return []byte(j.Key), nil
|
return []byte(j.Key), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, ok := t.Claims.(jwt.MapClaims)
|
claims, ok := t.Claims.(jwt.MapClaims)
|
||||||
if !ok || claims["role"] != "admin" { // Check role, only if its admin let it go
|
if !ok || claims["role"] != "admin" {
|
||||||
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func AddMigrations(db *gorm.DB) {
|
func AddMigrations(db *gorm.DB) {
|
||||||
db.AutoMigrate(&models.Post{}, &models.MediaAttachment{}, &models.Account{}, models.ComUser{})
|
db.AutoMigrate(&models.Post{}, &models.MediaAttachment{}, &models.Account{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,10 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
// Funny you are
|
|
||||||
type ComUser struct {
|
|
||||||
Id string
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
Email string
|
|
||||||
IsVerified bool
|
|
||||||
}
|
|
@@ -5,12 +5,19 @@ import (
|
|||||||
handlers_admin "CatsOfMastodonBotGo/internal/web/handlers/admin"
|
handlers_admin "CatsOfMastodonBotGo/internal/web/handlers/admin"
|
||||||
handlers_api "CatsOfMastodonBotGo/internal/web/handlers/api"
|
handlers_api "CatsOfMastodonBotGo/internal/web/handlers/api"
|
||||||
|
|
||||||
|
"github.com/gin-contrib/cors"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetupRouter(appContext *internal.AppContext) *gin.Engine {
|
func SetupRouter(appContext *internal.AppContext) *gin.Engine {
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
|
r.Use(cors.New(cors.Config{
|
||||||
|
AllowOrigins: []string{"https://extra-mama-chiz.surge.sh"}, // Just for test
|
||||||
|
AllowMethods: []string{"POST", "GET", "OPTIONS"},
|
||||||
|
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
|
||||||
|
AllowCredentials: true,
|
||||||
|
}))
|
||||||
|
|
||||||
adminDashboardHandler := handlers_admin.NewAdminDashboardHandler(appContext)
|
adminDashboardHandler := handlers_admin.NewAdminDashboardHandler(appContext)
|
||||||
apiHandler := handlers_api.NewApiEndpointHandler(appContext)
|
apiHandler := handlers_api.NewApiEndpointHandler(appContext)
|
||||||
@@ -19,8 +26,9 @@ func SetupRouter(appContext *internal.AppContext) *gin.Engine {
|
|||||||
|
|
||||||
// My man, this is done way more efficient and fast in .NET, specially the authentication part
|
// My man, this is done way more efficient and fast in .NET, specially the authentication part
|
||||||
admin.POST("/login", adminDashboardHandler.Login)
|
admin.POST("/login", adminDashboardHandler.Login)
|
||||||
admin.POST("/approve", appContext.Jwt.GinMiddleware() ,adminDashboardHandler.ApproveMedia)
|
admin.GET("/getmedia", appContext.Jwt.GinMiddleware(), adminDashboardHandler.GetMedia)
|
||||||
admin.POST("/reject" ,appContext.Jwt.GinMiddleware() , adminDashboardHandler.RejectMedia)
|
admin.POST("/approve", appContext.Jwt.GinMiddleware(), adminDashboardHandler.ApproveMedia)
|
||||||
|
admin.POST("/reject", appContext.Jwt.GinMiddleware(), adminDashboardHandler.RejectMedia)
|
||||||
|
|
||||||
api := r.Group("/api")
|
api := r.Group("/api")
|
||||||
|
|
||||||
|
@@ -60,13 +60,24 @@ func (ps *PostService) GetExistingAccountIds() []string {
|
|||||||
ps.db.Model(&models.Account{}).Pluck("acc_id", &existingAccountIds)
|
ps.db.Model(&models.Account{}).Pluck("acc_id", &existingAccountIds)
|
||||||
return existingAccountIds
|
return existingAccountIds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (*PostService) GetNewPosts(existingPostIds []string, posts []models.Post) []models.Post {
|
func (*PostService) GetNewPosts(existingPostIds []string, posts []models.Post) []models.Post {
|
||||||
var newPosts []models.Post = nil
|
var newPosts []models.Post = nil
|
||||||
for _, post := range posts {
|
for _, post := range posts {
|
||||||
if !arrayContains(existingPostIds, post.ID) && len(post.Attachments) > 0 && !post.Account.IsBot {
|
if !arrayContains(existingPostIds, post.ID) && len(post.Attachments) > 0 && !post.Account.IsBot {
|
||||||
|
var allImageMedia = true
|
||||||
|
for _, attachment := range post.Attachments {
|
||||||
|
if attachment.Type != "image" {
|
||||||
|
allImageMedia = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} // Inefficient but anyways
|
||||||
|
if allImageMedia {
|
||||||
newPosts = append(newPosts, post)
|
newPosts = append(newPosts, post)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return newPosts
|
return newPosts
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +105,12 @@ func (ps *PostService) GetRandomPost() models.Post {
|
|||||||
var post models.Post
|
var post models.Post
|
||||||
ps.db.
|
ps.db.
|
||||||
Preload("Account").
|
Preload("Account").
|
||||||
Preload("Attachments").
|
Preload("Attachments", "approved = ?", true).
|
||||||
Order("RANDOM()").
|
Order("RANDOM()").
|
||||||
First(&post)
|
First(&post)
|
||||||
|
if len(post.Attachments) > 0 {
|
||||||
|
post.Attachments = []models.MediaAttachment{post.Attachments[0]}
|
||||||
|
}
|
||||||
return post
|
return post
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,6 +126,18 @@ func (ps *PostService) RejectMedia(mediaId string) bool {
|
|||||||
Update("rejected", true).RowsAffected > 0
|
Update("rejected", true).RowsAffected > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a post which approve and rejet are false (For admin panel)
|
||||||
|
func (ps *PostService) GetMedia() models.MediaAttachment {
|
||||||
|
var media models.MediaAttachment
|
||||||
|
ps.db.Model(&models.MediaAttachment{}).
|
||||||
|
Where("approved = ?", false).
|
||||||
|
Where("rejected = ?", false).
|
||||||
|
Order("RANDOM()").
|
||||||
|
First(&media)
|
||||||
|
return media
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func arrayContains(arr []string, str string) bool {
|
func arrayContains(arr []string, str string) bool {
|
||||||
for _, a := range arr {
|
for _, a := range arr {
|
||||||
if a == str {
|
if a == str {
|
||||||
|
@@ -45,6 +45,11 @@ func (appContext *AdminDashboardHandler) RejectMedia(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (appContext *AdminDashboardHandler) GetMedia(c *gin.Context) {
|
||||||
|
media := appContext.AppContext.PostService.GetMedia()
|
||||||
|
c.JSON(http.StatusOK, media)
|
||||||
|
}
|
||||||
|
|
||||||
func (appContext *AdminDashboardHandler) Login(c *gin.Context) {
|
func (appContext *AdminDashboardHandler) Login(c *gin.Context) {
|
||||||
|
|
||||||
var input requestmodels.LoginInput
|
var input requestmodels.LoginInput
|
||||||
@@ -62,17 +67,13 @@ func (appContext *AdminDashboardHandler) Login(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SetCookie("token", token, 3600, "/", "", false, true)
|
c.JSON(http.StatusOK, gin.H{"message": "Login successful", "token": token})
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "Login successful"})
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
c.JSON(401, gin.H{
|
c.JSON(401, gin.H{
|
||||||
"YouAreOn": "Unauthorized",
|
"error": "wrong password",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(200, gin.H{
|
|
||||||
"YouAreOn": "Login",
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user