aligned users to new design

This commit is contained in:
ACoolName 2025-03-17 14:21:51 +02:00
parent f57888cb8e
commit ffdefae94f
9 changed files with 338 additions and 277 deletions

View File

@ -246,37 +246,6 @@ func (con Connection) verify(c *gin.Context) {
c.Redirect(303, fmt.Sprintf("http://%s/login", DOMAIN)) c.Redirect(303, fmt.Sprintf("http://%s/login", DOMAIN))
} }
func (con Connection) ServerAuthorized(permissions models.Permission) func(*gin.Context) bool {
return func(ctx *gin.Context) bool {
claims, exists := ctx.Get("claims")
if !exists {
return false
}
server_id := ctx.Param("server_id")
if server_id == "" {
return false
}
var serverData models.ServerData
con.DatabaseConnection.Database("Backend").Collection("Servers").FindOne(context.TODO(), bson.D{{Key: "Id", Value: server_id}}).Decode(&serverData)
if serverData.OwnerId == claims.(*AuthClaims).Username {
return true
}
userPermissions := serverData.UserPermissions[claims.(*AuthClaims).Username]
if userPermissions&permissions == permissions || userPermissions&models.Admin == models.Admin {
return true
}
return false
}
}
func LoadGroup(group *gin.RouterGroup, client *mongo.Client, config models.GlobalConfig) { func LoadGroup(group *gin.RouterGroup, client *mongo.Client, config models.GlobalConfig) {
connection := Connection{DatabaseConnection: client} connection := Connection{DatabaseConnection: client}

View File

@ -7,6 +7,7 @@ import (
"git.acooldomain.co/server-manager/backend-kubernetes-go/dbhandler" "git.acooldomain.co/server-manager/backend-kubernetes-go/dbhandler"
"git.acooldomain.co/server-manager/backend-kubernetes-go/models" "git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
@ -14,14 +15,11 @@ import (
type AuthUser struct { type AuthUser struct {
Username string `json:"username"` Username string `json:"username"`
Nickname string `json:"nickname"`
HashedPassword string `json:"hashed_password"` HashedPassword string `json:"hashed_password"`
Permissions models.Permission `json:"permissions"` Permissions models.Permission `json:"permissions"`
} MaxOwnedSevers uint `json:"max_owned_severs"`
Email string `json:"email"`
type Invite struct {
Email string `json:"email"`
InvitingUser string `json:"inviting_user"`
Token string `json:"token"`
} }
type UserPassAuthenticationDbHandler struct { type UserPassAuthenticationDbHandler struct {
@ -29,6 +27,29 @@ type UserPassAuthenticationDbHandler struct {
collection *mongo.Collection collection *mongo.Collection
} }
func (self *UserPassAuthenticationDbHandler) ListUsers(ctx context.Context) ([]models.User, error) {
cursor, err := self.collection.Find(ctx, nil)
if err != nil {
return nil, err
}
var authUsers []AuthUser
cursor.All(ctx, &authUsers)
modelUsers := make([]models.User, len(authUsers))
for i, authUser := range authUsers {
modelUsers[i] = models.User{
Username: authUser.Username,
Nickname: authUser.Nickname,
Email: authUser.Email,
}
}
return modelUsers, nil
}
func (self *UserPassAuthenticationDbHandler) AuthenticateUser(ctx context.Context, username string, password string) (models.Permission, error) { func (self *UserPassAuthenticationDbHandler) AuthenticateUser(ctx context.Context, username string, password string) (models.Permission, error) {
var user AuthUser var user AuthUser
err := self.collection.FindOne(ctx, bson.M{"username": username}).Decode(&user) err := self.collection.FindOne(ctx, bson.M{"username": username}).Decode(&user)
@ -55,6 +76,8 @@ func (self *UserPassAuthenticationDbHandler) CreateUser(
username string, username string,
password string, password string,
permissions models.Permission, permissions models.Permission,
email string,
maxOwnedServers uint,
) error { ) error {
hashedPassword, err := dbhandler.HashPassword(password) hashedPassword, err := dbhandler.HashPassword(password)
@ -66,6 +89,8 @@ func (self *UserPassAuthenticationDbHandler) CreateUser(
Username: username, Username: username,
HashedPassword: hashedPassword, HashedPassword: hashedPassword,
Permissions: permissions, Permissions: permissions,
Email: email,
MaxOwnedSevers: maxOwnedServers,
}) })
return err return err
@ -121,3 +146,63 @@ func NewUserPassAuthHandler(config models.MongoDBConfig) (*UserPassAuthenticatio
collection: client.Database(config.Database).Collection(config.Collection), collection: client.Database(config.Database).Collection(config.Collection),
}, nil }, nil
} }
type InviteToken struct {
Email string `json:"email"`
Token string `json:"token"`
Permissions models.Permission `json:"permissions"`
}
type InviteTokenDbHandler struct {
dbhandler.InviteTokenDbHandler
collection *mongo.Collection
}
func (self *ServersDbHandler) SaveInviteToken(ctx context.Context, email string, permissions models.Permission) (string, error) {
token := uuid.NewString()
_, err := self.collection.InsertOne(ctx, &InviteToken{
Permissions: permissions,
Email: email,
Token: token,
})
if err != nil {
return "", err
}
return token, nil
}
func (self *ServersDbHandler) GetInviteToken(ctx context.Context, token string) (*dbhandler.InviteToken, error) {
var inviteToken InviteToken
err := self.collection.FindOne(ctx, bson.M{"token": token}).Decode(&inviteToken)
if err != nil {
return nil, err
}
return &dbhandler.InviteToken{
Email: inviteToken.Email,
Permissions: inviteToken.Permissions,
Token: inviteToken.Token,
}, nil
}
func NewInviteTokenDbHandler(config models.MongoDBConfig) (*InviteTokenDbHandler, error) {
clientOptions := options.Client().ApplyURI(config.Url).SetAuth(options.Credential{
Username: config.Username,
Password: config.Password,
})
ctx, cancel := context.WithTimeoutCause(context.Background(), 30*time.Second, fmt.Errorf("Timeout"))
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
return nil, err
}
return &InviteTokenDbHandler{
collection: client.Database(config.Database).Collection(config.Collection),
}, nil
}

View File

@ -1,6 +1,8 @@
package dbhandler package dbhandler
import ( import (
"context"
"git.acooldomain.co/server-manager/backend-kubernetes-go/models" "git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@ -10,33 +12,31 @@ func HashPassword(password string) (string, error) {
return string(bytes), err return string(bytes), err
} }
type InviteUserRequest struct {
Email string `json:"email"`
InvitingUser string `json:"inviting_user"`
Permissions models.Permission `json:"permissions"`
}
type InviteToken struct { type InviteToken struct {
Email string `json:"email"` Email string
Permissions models.Permission `json:"permissions"` Permissions models.Permission
Token string `json:"token"` Token string
} }
type UserSignupRequest struct { type UserSignupRequest struct {
Token InviteToken `json:"token"` Token InviteToken
Username string `json:"username"` Username string
Password string `json:"password"` Password string
} }
type UserPassAuthanticationDbHandler interface { type UserPassAuthanticationDbHandler interface {
AuthenticateUser(username string, password string) (models.Permission, error) // Read Only
CreateUser(username string, password string, permissions models.Permission) error AuthenticateUser(ctx context.Context, username string, password string) (models.Permission, error)
RemoveUser(username string) error ListUsers(ctx context.Context) ([]models.User, error)
SetPermissions(username string, permissions models.Permission) error
SetPassword(username string, password string) error // Write
CreateUser(ctx context.Context, username string, password string, permissions models.Permission, email string, maxOwnedServers uint) error
RemoveUser(ctx context.Context, username string) error
SetPermissions(ctx context.Context, username string, permissions models.Permission) error
SetPassword(ctx context.Context, username string, password string) error
} }
type InviteTokenDbHandler interface { type InviteTokenDbHandler interface {
SaveInviteToken(token string, email string, permissions models.Permission) error SaveInviteToken(ctx context.Context, email string, permissions models.Permission) (string, error)
GetInviteToken(token string) (*InviteToken, error) GetInviteToken(ctx context.Context, token string) (*InviteToken, error)
} }

View File

@ -13,6 +13,8 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=

View File

@ -26,11 +26,17 @@ type OidcAuthConfig struct {
ClientSecret string `yaml:"client_secret"` ClientSecret string `yaml:"client_secret"`
} }
type UserPassAuthConfig struct { type InviteTokenDatabaseConfig struct {
Type DatabaseType `yaml:"type"` Type DatabaseType `yaml:"type"`
Mongo *MongoDBConfig `yaml:"mongo"` Mongo *MongoDBConfig `yaml:"mongo"`
} }
type UserPassAuthConfig struct {
Type DatabaseType `yaml:"type"`
Mongo *MongoDBConfig `yaml:"mongo"`
InviteTokenDatabase InviteTokenDatabaseConfig `yaml:"invite_token_database"`
}
type AuthenticationConfig struct { type AuthenticationConfig struct {
Type AuthMode `yaml:"type"` Type AuthMode `yaml:"type"`
Oidc OidcAuthConfig `yaml:"oidc"` Oidc OidcAuthConfig `yaml:"oidc"`

View File

@ -1,152 +1,71 @@
package servers package servers
import ( import (
"context"
"encoding/json"
"fmt"
"git.acooldomain.co/server-manager/backend-kubernetes-go/auth" "git.acooldomain.co/server-manager/backend-kubernetes-go/auth"
"git.acooldomain.co/server-manager/backend-kubernetes-go/db_handler/mongo"
"git.acooldomain.co/server-manager/backend-kubernetes-go/dbhandler"
instancemanager "git.acooldomain.co/server-manager/backend-kubernetes-go/instance_manager"
"git.acooldomain.co/server-manager/backend-kubernetes-go/instance_manager/docker"
"git.acooldomain.co/server-manager/backend-kubernetes-go/models" "git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume"
"github.com/docker/docker/client"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/mongo"
) )
func (con Connection) getBrowserInfo(volume volume.Volume) (*models.FileBrowser, error) {
serverInfo, err := con.getServerInfo(volume)
if err != nil {
return nil, err
}
containers, err := con.dockerClient.ContainerList(context.TODO(), container.ListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("label", "type=FILE_BROWSER"), filters.Arg("label", fmt.Sprintf("volume_id=%s", volume.Name))),
})
if err != nil || len(containers) == 0 {
return nil, nil
}
container := containers[0]
jsonData, err := json.Marshal(container.Labels)
if err != nil {
return nil, err
}
var browserInfo ContainerLabels
err = json.Unmarshal(jsonData, &browserInfo)
if err != nil {
return nil, err
}
return &models.FileBrowser{
Id: serverInfo.Id,
OwnerId: browserInfo.OwnerId,
ConnectedTo: *serverInfo,
Url: serverInfo.Id[:12] + ".browsers." + DOMAIN,
}, nil
}
func (con Connection) getBrowserInfoFromServerId(serverId string) (*models.FileBrowser, error) {
serverInfo, err := con.getServerInfoFromId(serverId)
if err != nil {
return nil, err
}
containers, err := con.dockerClient.ContainerList(context.TODO(), container.ListOptions{
All: true,
Filters: filters.NewArgs(filters.Arg("label", "type=FILE_BROWSER"), filters.Arg("label", fmt.Sprintf("volume_id=%s", serverInfo.Id))),
})
if err != nil || len(containers) == 0 {
return nil, nil
}
container := containers[0]
jsonData, err := json.Marshal(container.Labels)
if err != nil {
return nil, err
}
var browserInfo ContainerLabels
err = json.Unmarshal(jsonData, &browserInfo)
if err != nil {
return nil, err
}
return &models.FileBrowser{
Id: serverInfo.Id,
OwnerId: browserInfo.OwnerId,
ConnectedTo: *serverInfo,
Url: serverInfo.Id[:12] + ".browsers." + DOMAIN,
}, nil
}
func (con Connection) GetBrowsers(ctx *gin.Context) { func (con Connection) GetBrowsers(ctx *gin.Context) {
volumes, err := con.dockerClient.VolumeList( fileBrowsers, err := con.InstanceManager.ListFileBrowsers(ctx)
context.TODO(),
volume.ListOptions{
Filters: filters.NewArgs(filters.Arg("label", "type=GAME")),
},
)
if err != nil {
ctx.AbortWithError(500, err)
}
var servers []models.FileBrowser = make([]models.FileBrowser, 0, len(volumes.Volumes))
for _, volume := range volumes.Volumes {
browserInfo, err := con.getBrowserInfo(*volume)
if err != nil {
ctx.AbortWithError(500, err)
}
if browserInfo == nil {
continue
}
servers = append(servers, *browserInfo)
}
if err != nil { if err != nil {
ctx.AbortWithError(500, err) ctx.AbortWithError(500, err)
} }
ctx.JSON(200, servers) ctx.JSON(200, fileBrowsers)
} }
func (con Connection) StopBrowser(ctx *gin.Context) { func (con Connection) StopBrowser(ctx *gin.Context) {
serverId := ctx.Param("server_id") serverId := ctx.Param("server_id")
containersList, err := con.dockerClient.ContainerList(context.TODO(), container.ListOptions{ err := con.InstanceManager.StopFileBrowser(ctx, serverId)
Filters: filters.NewArgs(filters.Arg("label", "volume_id="+serverId), filters.Arg("label", "type=FILE_BROWSER")),
})
if err != nil { if err != nil {
ctx.AbortWithError(500, err) ctx.AbortWithError(500, err)
return return
} }
if len(containersList) == 0 {
ctx.Status(200)
return
}
for _, containerData := range containersList {
con.dockerClient.ContainerStop(context.TODO(), containerData.ID, container.StopOptions{})
}
ctx.Status(200) ctx.Status(200)
} }
func LoadBrowsersGroup(group *gin.RouterGroup, mongo_client *mongo.Client, config models.GlobalConfig) { func LoadBrowsersGroup(group *gin.RouterGroup, config models.GlobalConfig) {
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) var instanceManager instancemanager.InstanceManager
if err != nil { var serversDbHandler dbhandler.ServersDbHandler
panic(err) var serversAuthorizationHandler dbhandler.ServersAuthorizationDbHandler
}
defer apiClient.Close() var err error
if config.InstanceManager.Type == models.DOCKER {
instanceManager, err = docker.NewInstanceManager(config.InstanceManager.Docker)
if err != nil {
panic(err)
}
}
if config.ServersDatabase.Type == models.MONGO {
serversDbHandler, err = mongo.NewServersDbHandler(*config.ServersDatabase.Mongo)
if err != nil {
panic(err)
}
}
if config.ServersAuthorizationDatabase.Type == models.MONGO {
serversAuthorizationHandler, err = mongo.NewAuthorizationHandler(*config.ServersAuthorizationDatabase.Mongo)
if err != nil {
panic(err)
}
}
connection := Connection{
ServersDbHandler: serversDbHandler,
ServerAuthorization: serversAuthorizationHandler,
InstanceManager: instanceManager,
}
connection := Connection{databaseConnection: mongo_client, dockerClient: apiClient}
authConnection := auth.Connection{DatabaseConnection: mongo_client}
group.GET("", auth.AuthorizedTo(0), connection.GetBrowsers) group.GET("", auth.AuthorizedTo(0), connection.GetBrowsers)
group.POST("/:server_id/stop", auth.AuthorizedTo(models.Browse, authConnection.ServerAuthorized(models.Browse)), connection.StopBrowser) group.POST("/:server_id/stop", auth.AuthorizedTo(models.Browse), connection.ServerAuthorized(models.Browse), connection.StopBrowser)
} }

View File

@ -1,46 +1,41 @@
package servers package servers
import ( import (
"context"
"fmt" "fmt"
"strings"
"git.acooldomain.co/server-manager/backend-kubernetes-go/auth" "git.acooldomain.co/server-manager/backend-kubernetes-go/auth"
"git.acooldomain.co/server-manager/backend-kubernetes-go/db_handler/mongo"
"git.acooldomain.co/server-manager/backend-kubernetes-go/dbhandler"
instancemanager "git.acooldomain.co/server-manager/backend-kubernetes-go/instance_manager"
"git.acooldomain.co/server-manager/backend-kubernetes-go/instance_manager/docker"
"git.acooldomain.co/server-manager/backend-kubernetes-go/models" "git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/mongo"
) )
type ImageData struct { type ImageData struct {
Id string Id string `json:"Id"`
Name string Name string `json:"Name"`
Version string Version string `json:"Version"`
DisplayName string DisplayName string `json:"DisplayName"`
} }
func convertImageToImageData(imageSummary image.Summary) *ImageData { func convertImageToImageData(instanceImage instancemanager.Image) *ImageData {
if len(imageSummary.RepoTags) == 0 { imageId := instanceImage.Registry + ":" + instanceImage.Tag
return nil
}
imageId := imageSummary.RepoTags[0]
splitImageId := strings.Split(imageId, ":")
imageName, imageVersion := splitImageId[0], splitImageId[1]
return &ImageData{ return &ImageData{
Id: imageId, Id: imageId,
Name: imageName, Name: instanceImage.Registry,
Version: imageVersion, Version: instanceImage.Tag,
DisplayName: fmt.Sprintf("%s %s", imageName, imageVersion), DisplayName: fmt.Sprintf("%s %s", instanceImage.Registry, instanceImage.Tag),
} }
} }
func (con Connection) GetImages(c *gin.Context) { func (con Connection) GetImages(ctx *gin.Context) {
images, err := con.dockerClient.ImageList(context.TODO(), image.ListOptions{Filters: filters.NewArgs(filters.Arg("label", "type=GAME"))}) images, err := con.InstanceManager.ListImages(ctx)
if err != nil { if err != nil {
c.AbortWithError(500, err) ctx.AbortWithError(500, err)
return return
} }
imagesData := make([]ImageData, 0, len(images)) imagesData := make([]ImageData, 0, len(images))
for _, imageSummary := range images { for _, imageSummary := range images {
@ -52,16 +47,43 @@ func (con Connection) GetImages(c *gin.Context) {
imagesData = append(imagesData, *imageData) imagesData = append(imagesData, *imageData)
} }
c.JSON(200, imagesData) ctx.JSON(200, imagesData)
} }
func LoadeImagesGroup(group *gin.RouterGroup, mongo_client *mongo.Client, config models.GlobalConfig) { func LoadeImagesGroup(group *gin.RouterGroup, config models.GlobalConfig) {
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) var instanceManager instancemanager.InstanceManager
if err != nil { var serversDbHandler dbhandler.ServersDbHandler
panic(err) var serversAuthorizationHandler dbhandler.ServersAuthorizationDbHandler
}
defer apiClient.Close() var err error
if config.InstanceManager.Type == models.DOCKER {
instanceManager, err = docker.NewInstanceManager(config.InstanceManager.Docker)
if err != nil {
panic(err)
}
}
if config.ServersDatabase.Type == models.MONGO {
serversDbHandler, err = mongo.NewServersDbHandler(*config.ServersDatabase.Mongo)
if err != nil {
panic(err)
}
}
if config.ServersAuthorizationDatabase.Type == models.MONGO {
serversAuthorizationHandler, err = mongo.NewAuthorizationHandler(*config.ServersAuthorizationDatabase.Mongo)
if err != nil {
panic(err)
}
}
connection := Connection{
ServersDbHandler: serversDbHandler,
ServerAuthorization: serversAuthorizationHandler,
InstanceManager: instanceManager,
}
connection := Connection{databaseConnection: mongo_client, dockerClient: apiClient}
group.GET("", auth.AuthorizedTo(0), connection.GetImages) group.GET("", auth.AuthorizedTo(0), connection.GetImages)
} }

View File

@ -1,7 +1,6 @@
package servers package servers
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -19,7 +18,6 @@ import (
"git.acooldomain.co/server-manager/backend-kubernetes-go/models" "git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
) )
var upgrader = websocket.Upgrader{ var upgrader = websocket.Upgrader{
@ -67,6 +65,37 @@ type CreateServerRequest struct {
Nickname string `json:"Nickname"` Nickname string `json:"Nickname"`
} }
func (con Connection) ServerAuthorized(permissions models.Permission) func(*gin.Context) {
return func(ctx *gin.Context) {
claimsPointer, exists := ctx.Get("claims")
if !exists {
ctx.AbortWithStatus(403)
return
}
claims := claimsPointer.(*auth.AuthClaims)
serverId := ctx.Param("server_id")
if serverId == "" {
ctx.AbortWithStatus(403)
return
}
userPermissions, err := con.ServerAuthorization.GetPermissions(ctx, claims.Username, serverId)
if err != nil {
ctx.AbortWithError(500, err)
return
}
if userPermissions&permissions == permissions || userPermissions&models.Admin == models.Admin {
return
}
ctx.AbortWithStatus(403)
return
}
}
func (con Connection) CreateServer(ctx *gin.Context) { func (con Connection) CreateServer(ctx *gin.Context) {
claims, exists := ctx.Get("claims") claims, exists := ctx.Get("claims")
if !exists { if !exists {
@ -109,6 +138,12 @@ func (con Connection) CreateServer(ctx *gin.Context) {
return return
} }
err = con.ServerAuthorization.AddPermissions(ctx, serverClaims.Username, instanceServer.Id, models.Admin)
if err != nil {
ctx.AbortWithError(500, err)
return
}
ctx.JSON(200, instanceServer.Id) ctx.JSON(200, instanceServer.Id)
} }
@ -540,17 +575,16 @@ func LoadGroup(group *gin.RouterGroup, config models.GlobalConfig) {
ServerAuthorization: serversAuthorizationHandler, ServerAuthorization: serversAuthorizationHandler,
InstanceManager: instanceManager, InstanceManager: instanceManager,
} }
authConnection := auth.Connection{}
group.POST("/:server_id/start", auth.AuthorizedTo(models.Start, authConnection.ServerAuthorized(models.Start)), connection.StartServer) group.POST("/:server_id/start", auth.AuthorizedTo(models.Start), connection.ServerAuthorized(models.Start), connection.StartServer)
group.POST("", auth.AuthorizedTo(models.Create), connection.CreateServer) group.POST("", auth.AuthorizedTo(models.Create), connection.CreateServer)
group.GET("", auth.AuthorizedTo(0), connection.GetServers) group.GET("", auth.AuthorizedTo(0), connection.GetServers)
group.POST("/:server_id/stop", auth.AuthorizedTo(models.Stop, authConnection.ServerAuthorized(models.Stop)), connection.StopServer) group.POST("/:server_id/stop", auth.AuthorizedTo(models.Stop), connection.ServerAuthorized(models.Stop), connection.StopServer)
group.DELETE("/:server_id", auth.AuthorizedTo(models.Delete, authConnection.ServerAuthorized(models.Delete)), connection.DeleteServer) group.DELETE("/:server_id", auth.AuthorizedTo(models.Delete), connection.ServerAuthorized(models.Delete), connection.DeleteServer)
group.POST("/:server_id/run_command", auth.AuthorizedTo(models.RunCommand, authConnection.ServerAuthorized(models.RunCommand)), connection.RunCommand) group.POST("/:server_id/run_command", auth.AuthorizedTo(models.RunCommand), connection.ServerAuthorized(models.RunCommand), connection.RunCommand)
group.GET("/:server_id/attach", auth.AuthorizedTo(models.RunCommand, authConnection.ServerAuthorized(models.RunCommand)), connection.AttachServer) group.GET("/:server_id/attach", auth.AuthorizedTo(models.RunCommand), connection.ServerAuthorized(models.RunCommand), connection.AttachServer)
group.PATCH("/:server_id", auth.AuthorizedTo(models.Admin, authConnection.ServerAuthorized(models.Admin)), connection.UpdateServer) group.PATCH("/:server_id", auth.AuthorizedTo(models.Admin), connection.ServerAuthorized(models.Admin), connection.UpdateServer)
group.POST("/:server_id/browse", auth.AuthorizedTo(models.Browse, authConnection.ServerAuthorized(models.Admin)), connection.BrowseServer) group.POST("/:server_id/browse", auth.AuthorizedTo(models.Browse), connection.ServerAuthorized(models.Admin), connection.BrowseServer)
group.GET("/:server_id/permissions", auth.AuthorizedTo(models.Browse, authConnection.ServerAuthorized(models.Admin)), connection.GetServerUserPermissions) group.GET("/:server_id/permissions", auth.AuthorizedTo(models.Browse), connection.ServerAuthorized(models.Admin), connection.GetServerUserPermissions)
group.POST("/:server_id/permissions", auth.AuthorizedTo(models.Browse, authConnection.ServerAuthorized(models.Admin)), connection.SetServerUserPermissions) group.POST("/:server_id/permissions", auth.AuthorizedTo(models.Browse), connection.ServerAuthorized(models.Admin), connection.SetServerUserPermissions)
} }

View File

@ -1,49 +1,49 @@
package users package users
import ( import (
"context"
"encoding/json" "encoding/json"
"net/http" "net/http"
"git.acooldomain.co/server-manager/backend-kubernetes-go/auth" "git.acooldomain.co/server-manager/backend-kubernetes-go/auth"
"git.acooldomain.co/server-manager/backend-kubernetes-go/db_handler/mongo"
"git.acooldomain.co/server-manager/backend-kubernetes-go/dbhandler" "git.acooldomain.co/server-manager/backend-kubernetes-go/dbhandler"
"git.acooldomain.co/server-manager/backend-kubernetes-go/mail" "git.acooldomain.co/server-manager/backend-kubernetes-go/mail"
"git.acooldomain.co/server-manager/backend-kubernetes-go/models" "git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
) )
type Connection struct { type Connection struct {
connection *dbhandler.UsersDBHandler userPassAuthHandler dbhandler.UserPassAuthanticationDbHandler
config *models.GlobalConfig tokenHandler dbhandler.InviteTokenDbHandler
mailClient mail.MailClient
config *models.GlobalConfig
} }
type UserResponse struct { type UserResponse struct {
Username string Username string `json:"Username"`
Email string Email string `json:"Email"`
Permissions models.Permission Permissions models.Permission `json:"Permissions"`
} }
func (con Connection) GetUsers(c *gin.Context) { func (con Connection) GetUsers(ctx *gin.Context) {
users, err := (*con.connection).ListUsers() users, err := con.userPassAuthHandler.ListUsers(ctx)
if err != nil { if err != nil {
panic(err) ctx.AbortWithError(500, err)
}
c.JSON(http.StatusOK, users)
}
func (con Connection) GetUser(c *gin.Context) {
claims, exists := c.Get("claims")
if !exists {
c.AbortWithStatus(505)
return return
} }
c.IndentedJSON(http.StatusOK, UserResponse{ ctx.JSON(http.StatusOK, users)
}
func (con Connection) GetUser(ctx *gin.Context) {
claims, exists := ctx.Get("claims")
if !exists {
ctx.AbortWithStatus(403)
return
}
ctx.IndentedJSON(http.StatusOK, UserResponse{
Username: claims.(*auth.AuthClaims).Username, Username: claims.(*auth.AuthClaims).Username,
Permissions: claims.(*auth.AuthClaims).Permissions, Permissions: claims.(*auth.AuthClaims).Permissions,
}) })
@ -54,63 +54,87 @@ type InviteUser struct {
Permissions models.Permission `json:"Permissions"` Permissions models.Permission `json:"Permissions"`
} }
func (con Connection) InviteUser(c *gin.Context) { func (con Connection) InviteUser(ctx *gin.Context) {
var request InviteUser var request InviteUser
json.NewDecoder(c.Request.Body).Decode(&request) json.NewDecoder(ctx.Request.Body).Decode(&request)
token := uuid.NewString()
token, err := con.tokenHandler.SaveInviteToken(ctx, request.Email, request.Permissions)
err := mail.SendMail(request.Email, "You've been invited to join", "please open this link https://games.acooldomain.co/signup?token="+token)
if err != nil { if err != nil {
c.AbortWithError(500, err) ctx.AbortWithError(500, err)
return return
} }
con.connection.Database("Backend").Collection("Tokens").InsertOne(context.TODO(), auth.InviteToken{
Email: request.Email, err = con.mailClient.SendMail(request.Email, "You've been invited to join", "please open this link https://games.acooldomain.co/signup?token="+token)
Permissions: request.Permissions, if err != nil {
Token: token, ctx.AbortWithError(500, err)
}) return
c.JSON(200, "OK") }
ctx.JSON(200, "OK")
} }
type SetUserPermissionsRequest struct { type SetUserPermissionsRequest struct {
Permissions models.Permission Permissions models.Permission `json:"Permissions"`
} }
func (con Connection) SetUserPermissions(c *gin.Context) { func (con Connection) SetUserPermissions(ctx *gin.Context) {
var request SetUserPermissionsRequest var request SetUserPermissionsRequest
json.NewDecoder(c.Request.Body).Decode(&request) json.NewDecoder(ctx.Request.Body).Decode(&request)
username := c.Param("user_id") username := ctx.Param("user_id")
_, err := con.connection.Database("Backend").Collection("Users").UpdateOne( err := con.userPassAuthHandler.SetPermissions(ctx, username, request.Permissions)
context.TODO(),
bson.D{{Key: "Username", Value: username}},
bson.D{{Key: "$set", Value: bson.D{{Key: "Permissions", Value: request.Permissions}}}},
)
if err != nil { if err != nil {
c.AbortWithError(500, err) ctx.AbortWithError(500, err)
return return
} }
c.JSON(200, "OK") ctx.JSON(200, "OK")
} }
func (con Connection) DeleteUser(c *gin.Context) { func (con Connection) DeleteUser(ctx *gin.Context) {
username := c.Param("user_id") username := ctx.Param("user_id")
err := con.userPassAuthHandler.RemoveUser(ctx, username)
_, err := con.connection.Database("Backend").Collection("Users").DeleteOne(
context.TODO(),
bson.D{{Key: "Username", Value: username}},
)
if err != nil { if err != nil {
c.AbortWithError(500, err) ctx.AbortWithError(500, err)
return return
} }
c.JSON(200, "OK") ctx.JSON(200, "OK")
} }
func LoadGroup(group *gin.RouterGroup, client *mongo.Client, config models.GlobalConfig) { func LoadGroup(group *gin.RouterGroup, config models.GlobalConfig) {
connection := Connection{connection: client} var userAuthHandler dbhandler.UserPassAuthanticationDbHandler
var inviteHandler dbhandler.InviteTokenDbHandler
var mailClient mail.MailClient
var err error
if config.Authentication.UserPass.Type == models.MONGO {
userAuthHandler, err = mongo.NewUserPassAuthHandler(*config.Authentication.UserPass.Mongo)
if err != nil {
panic(err)
}
}
if config.Authentication.UserPass.InviteTokenDatabase.Type == models.MONGO {
inviteHandler, err = mongo.NewInviteTokenDbHandler(*config.Authentication.UserPass.Mongo)
if err != nil {
panic(err)
}
}
mailClient = *mail.NewMailClient(config.Email)
connection := Connection{
userPassAuthHandler: userAuthHandler,
tokenHandler: inviteHandler,
mailClient: mailClient,
config: &config,
}
group.GET("", auth.AuthorizedTo(0), connection.GetUsers) group.GET("", auth.AuthorizedTo(0), connection.GetUsers)
group.GET("/@me", auth.AuthorizedTo(0), connection.GetUser) group.GET("/@me", auth.AuthorizedTo(0), connection.GetUser)
group.POST("", auth.AuthorizedTo(models.Admin), connection.InviteUser) group.POST("", auth.AuthorizedTo(models.Admin), connection.InviteUser)