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))
}
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) {
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/models"
"github.com/google/uuid"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
@ -14,14 +15,11 @@ import (
type AuthUser struct {
Username string `json:"username"`
Nickname string `json:"nickname"`
HashedPassword string `json:"hashed_password"`
Permissions models.Permission `json:"permissions"`
}
type Invite struct {
Email string `json:"email"`
InvitingUser string `json:"inviting_user"`
Token string `json:"token"`
MaxOwnedSevers uint `json:"max_owned_severs"`
Email string `json:"email"`
}
type UserPassAuthenticationDbHandler struct {
@ -29,6 +27,29 @@ type UserPassAuthenticationDbHandler struct {
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) {
var user AuthUser
err := self.collection.FindOne(ctx, bson.M{"username": username}).Decode(&user)
@ -55,6 +76,8 @@ func (self *UserPassAuthenticationDbHandler) CreateUser(
username string,
password string,
permissions models.Permission,
email string,
maxOwnedServers uint,
) error {
hashedPassword, err := dbhandler.HashPassword(password)
@ -66,6 +89,8 @@ func (self *UserPassAuthenticationDbHandler) CreateUser(
Username: username,
HashedPassword: hashedPassword,
Permissions: permissions,
Email: email,
MaxOwnedSevers: maxOwnedServers,
})
return err
@ -121,3 +146,63 @@ func NewUserPassAuthHandler(config models.MongoDBConfig) (*UserPassAuthenticatio
collection: client.Database(config.Database).Collection(config.Collection),
}, 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
import (
"context"
"git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"golang.org/x/crypto/bcrypt"
)
@ -10,33 +12,31 @@ func HashPassword(password string) (string, error) {
return string(bytes), err
}
type InviteUserRequest struct {
Email string `json:"email"`
InvitingUser string `json:"inviting_user"`
Permissions models.Permission `json:"permissions"`
}
type InviteToken struct {
Email string `json:"email"`
Permissions models.Permission `json:"permissions"`
Token string `json:"token"`
Email string
Permissions models.Permission
Token string
}
type UserSignupRequest struct {
Token InviteToken `json:"token"`
Username string `json:"username"`
Password string `json:"password"`
Token InviteToken
Username string
Password string
}
type UserPassAuthanticationDbHandler interface {
AuthenticateUser(username string, password string) (models.Permission, error)
CreateUser(username string, password string, permissions models.Permission) error
RemoveUser(username string) error
SetPermissions(username string, permissions models.Permission) error
SetPassword(username string, password string) error
// Read Only
AuthenticateUser(ctx context.Context, username string, password string) (models.Permission, error)
ListUsers(ctx context.Context) ([]models.User, 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 {
SaveInviteToken(token string, email string, permissions models.Permission) error
GetInviteToken(token string) (*InviteToken, error)
SaveInviteToken(ctx context.Context, email string, permissions models.Permission) (string, 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/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/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/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=

View File

@ -26,11 +26,17 @@ type OidcAuthConfig struct {
ClientSecret string `yaml:"client_secret"`
}
type UserPassAuthConfig struct {
type InviteTokenDatabaseConfig struct {
Type DatabaseType `yaml:"type"`
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 AuthMode `yaml:"type"`
Oidc OidcAuthConfig `yaml:"oidc"`

View File

@ -1,152 +1,71 @@
package servers
import (
"context"
"encoding/json"
"fmt"
"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"
"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"
"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) {
volumes, err := con.dockerClient.VolumeList(
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)
}
fileBrowsers, err := con.InstanceManager.ListFileBrowsers(ctx)
if err != nil {
ctx.AbortWithError(500, err)
}
ctx.JSON(200, servers)
ctx.JSON(200, fileBrowsers)
}
func (con Connection) StopBrowser(ctx *gin.Context) {
serverId := ctx.Param("server_id")
containersList, err := con.dockerClient.ContainerList(context.TODO(), container.ListOptions{
Filters: filters.NewArgs(filters.Arg("label", "volume_id="+serverId), filters.Arg("label", "type=FILE_BROWSER")),
})
err := con.InstanceManager.StopFileBrowser(ctx, serverId)
if err != nil {
ctx.AbortWithError(500, err)
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)
}
func LoadBrowsersGroup(group *gin.RouterGroup, mongo_client *mongo.Client, config models.GlobalConfig) {
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer apiClient.Close()
func LoadBrowsersGroup(group *gin.RouterGroup, config models.GlobalConfig) {
var instanceManager instancemanager.InstanceManager
var serversDbHandler dbhandler.ServersDbHandler
var serversAuthorizationHandler dbhandler.ServersAuthorizationDbHandler
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.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
import (
"context"
"fmt"
"strings"
"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"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/mongo"
)
type ImageData struct {
Id string
Name string
Version string
DisplayName string
Id string `json:"Id"`
Name string `json:"Name"`
Version string `json:"Version"`
DisplayName string `json:"DisplayName"`
}
func convertImageToImageData(imageSummary image.Summary) *ImageData {
if len(imageSummary.RepoTags) == 0 {
return nil
}
imageId := imageSummary.RepoTags[0]
splitImageId := strings.Split(imageId, ":")
imageName, imageVersion := splitImageId[0], splitImageId[1]
func convertImageToImageData(instanceImage instancemanager.Image) *ImageData {
imageId := instanceImage.Registry + ":" + instanceImage.Tag
return &ImageData{
Id: imageId,
Name: imageName,
Version: imageVersion,
DisplayName: fmt.Sprintf("%s %s", imageName, imageVersion),
Name: instanceImage.Registry,
Version: instanceImage.Tag,
DisplayName: fmt.Sprintf("%s %s", instanceImage.Registry, instanceImage.Tag),
}
}
func (con Connection) GetImages(c *gin.Context) {
images, err := con.dockerClient.ImageList(context.TODO(), image.ListOptions{Filters: filters.NewArgs(filters.Arg("label", "type=GAME"))})
func (con Connection) GetImages(ctx *gin.Context) {
images, err := con.InstanceManager.ListImages(ctx)
if err != nil {
c.AbortWithError(500, err)
ctx.AbortWithError(500, err)
return
}
imagesData := make([]ImageData, 0, len(images))
for _, imageSummary := range images {
@ -52,16 +47,43 @@ func (con Connection) GetImages(c *gin.Context) {
imagesData = append(imagesData, *imageData)
}
c.JSON(200, imagesData)
ctx.JSON(200, imagesData)
}
func LoadeImagesGroup(group *gin.RouterGroup, mongo_client *mongo.Client, config models.GlobalConfig) {
apiClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
panic(err)
}
defer apiClient.Close()
func LoadeImagesGroup(group *gin.RouterGroup, config models.GlobalConfig) {
var instanceManager instancemanager.InstanceManager
var serversDbHandler dbhandler.ServersDbHandler
var serversAuthorizationHandler dbhandler.ServersAuthorizationDbHandler
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)
}

View File

@ -1,7 +1,6 @@
package servers
import (
"context"
"encoding/json"
"errors"
"fmt"
@ -19,7 +18,6 @@ import (
"git.acooldomain.co/server-manager/backend-kubernetes-go/models"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)
var upgrader = websocket.Upgrader{
@ -67,6 +65,37 @@ type CreateServerRequest struct {
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) {
claims, exists := ctx.Get("claims")
if !exists {
@ -109,6 +138,12 @@ func (con Connection) CreateServer(ctx *gin.Context) {
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)
}
@ -540,17 +575,16 @@ func LoadGroup(group *gin.RouterGroup, config models.GlobalConfig) {
ServerAuthorization: serversAuthorizationHandler,
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.GET("", auth.AuthorizedTo(0), connection.GetServers)
group.POST("/:server_id/stop", auth.AuthorizedTo(models.Stop, authConnection.ServerAuthorized(models.Stop)), connection.StopServer)
group.DELETE("/:server_id", auth.AuthorizedTo(models.Delete, authConnection.ServerAuthorized(models.Delete)), connection.DeleteServer)
group.POST("/:server_id/run_command", auth.AuthorizedTo(models.RunCommand, authConnection.ServerAuthorized(models.RunCommand)), connection.RunCommand)
group.GET("/:server_id/attach", auth.AuthorizedTo(models.RunCommand, authConnection.ServerAuthorized(models.RunCommand)), connection.AttachServer)
group.PATCH("/:server_id", auth.AuthorizedTo(models.Admin, authConnection.ServerAuthorized(models.Admin)), connection.UpdateServer)
group.POST("/:server_id/browse", auth.AuthorizedTo(models.Browse, authConnection.ServerAuthorized(models.Admin)), connection.BrowseServer)
group.GET("/:server_id/permissions", auth.AuthorizedTo(models.Browse, authConnection.ServerAuthorized(models.Admin)), connection.GetServerUserPermissions)
group.POST("/:server_id/permissions", auth.AuthorizedTo(models.Browse, authConnection.ServerAuthorized(models.Admin)), connection.SetServerUserPermissions)
group.POST("/:server_id/stop", auth.AuthorizedTo(models.Stop), connection.ServerAuthorized(models.Stop), connection.StopServer)
group.DELETE("/:server_id", auth.AuthorizedTo(models.Delete), connection.ServerAuthorized(models.Delete), connection.DeleteServer)
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), connection.ServerAuthorized(models.RunCommand), connection.AttachServer)
group.PATCH("/:server_id", auth.AuthorizedTo(models.Admin), connection.ServerAuthorized(models.Admin), connection.UpdateServer)
group.POST("/:server_id/browse", auth.AuthorizedTo(models.Browse), connection.ServerAuthorized(models.Admin), connection.BrowseServer)
group.GET("/:server_id/permissions", auth.AuthorizedTo(models.Browse), connection.ServerAuthorized(models.Admin), connection.GetServerUserPermissions)
group.POST("/:server_id/permissions", auth.AuthorizedTo(models.Browse), connection.ServerAuthorized(models.Admin), connection.SetServerUserPermissions)
}

View File

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