Skip to content

Commit 85087d5

Browse files
committed
feature: Permission and role system
1 parent 589ab83 commit 85087d5

File tree

8 files changed

+265
-42
lines changed

8 files changed

+265
-42
lines changed

app/middleware/permission/new.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package permission
2+
3+
import (
4+
"github.com/gofiber/fiber/v2"
5+
"github.com/limanmys/render-engine/app/models"
6+
"github.com/limanmys/render-engine/internal/liman"
7+
"github.com/limanmys/render-engine/pkg/helpers"
8+
)
9+
10+
func New() fiber.Handler {
11+
return permission
12+
}
13+
14+
func permission(c *fiber.Ctx) error {
15+
if helpers.Env("LIMAN_RESTRICTED", "false") == "true" {
16+
return c.Next()
17+
}
18+
19+
user, err := liman.GetUser(&models.User{
20+
ID: c.Locals("user_id").(string),
21+
})
22+
if err != nil {
23+
return fiber.NewError(fiber.StatusInternalServerError, "error while getting the user")
24+
}
25+
26+
if user.Status == 1 {
27+
return c.Next()
28+
}
29+
30+
perms, err := liman.GetObjectPermissions(user)
31+
if err != nil {
32+
return fiber.NewError(fiber.StatusInternalServerError, "error while getting the object permissions")
33+
}
34+
35+
if len(c.FormValue("server_id")) > 0 {
36+
if !helpers.Contains(perms, c.FormValue("server_id")) {
37+
return fiber.NewError(fiber.StatusForbidden, "you have no permission to do this")
38+
}
39+
}
40+
41+
if len(c.FormValue("extension_id")) > 0 {
42+
extensionID := c.FormValue("extension_id")
43+
if !helpers.CheckUUID(extensionID) {
44+
extension, err := liman.GetExtension(&models.Extension{Name: extensionID})
45+
if err != nil {
46+
return err
47+
}
48+
49+
extensionID = extension.ID
50+
}
51+
52+
if !helpers.Contains(perms, extensionID) || len(extensionID) < 1 {
53+
return fiber.NewError(fiber.StatusForbidden, "you have no permission to do this")
54+
}
55+
56+
c.Locals("extension_id", extensionID)
57+
}
58+
59+
return c.Next()
60+
}

app/models/extension.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ type Extension struct {
55
ID string `json:"id"`
66
Name string `json:"name"`
77
Version string `json:"version"`
8-
Icon string `json:"icon"`
8+
Icon string `json:"-"`
99
Service string `json:"service"`
10-
CreatedAt string `json:"created_at"`
11-
UpdatedAt string `json:"updated_at"`
12-
Order int `json:"order"`
10+
CreatedAt string `json:"-"`
11+
UpdatedAt string `json:"-"`
12+
Order int `json:"-"`
1313
SslPorts string `json:"sslPorts" pg:"sslPorts"`
1414
Issuer string `json:"issuer"`
15-
Language string `json:"language"`
15+
Language string `json:"-"`
1616
Support string `json:"support"`
1717
Displays string `json:"displays"`
1818
Status string `json:"status"`

app/models/permission.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package models
2+
3+
type Permission struct {
4+
ID string `json:"id"`
5+
CreatedAt string `json:"created_at"`
6+
UpdatedAt string `json:"updated_at"`
7+
Type string `json:"type"`
8+
Key string `json:"key"`
9+
Value string `json:"value"`
10+
Extra string `json:"extra"`
11+
Blame string `json:"blame"`
12+
MorphID string `json:"morph_id"`
13+
MorphType string `json:"morph_type"`
14+
}
15+
16+
func (Permission) TableName() string {
17+
return "permissions"
18+
}

app/models/role_users.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package models
2+
3+
type RoleUsers struct {
4+
ID string `json:"id"`
5+
UserID string `json:"user_id"`
6+
RoleID string `json:"role_id"`
7+
CreatedAt string `json:"created_at"`
8+
UpdatedAt string `json:"updated_at"`
9+
Type string `json:"type"`
10+
}
11+
12+
func (RoleUsers) TableName() string {
13+
return "role_users"
14+
}

app/models/server.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ type Server struct {
66
Name string `json:"name"`
77
Type string `json:"type"`
88
IPAddress string `json:"ip_address"`
9-
City string `json:"city"`
9+
City string `json:"-"`
1010
ControlPort string `json:"control_port"`
11-
UserID string `json:"user_id"`
12-
CreatedAt string `json:"created_at"`
13-
UpdatedAt string `json:"updated_at"`
11+
UserID string `json:"-"`
12+
CreatedAt string `json:"-"`
13+
UpdatedAt string `json:"-"`
1414
Os string `json:"os"`
1515
Enabled string `json:"enabled"`
1616
KeyPort int `json:"key_port"`

app/models/user.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ type User struct {
55
ID string `json:"id"`
66
Name string `json:"name"`
77
Email string `json:"email"`
8-
Password string `json:"password" gorm:"-"`
8+
Password string `json:"-" gorm:"-"`
99
Status int `json:"status"`
10-
LastLoginAt string `json:"last_login_at" gorm:"-"`
11-
RememberToken string `json:"remember_token" gorm:"-"`
12-
LastLoginIP string `json:"last_login_ip" gorm:"-"`
13-
CreatedAt string `json:"created_at"`
14-
UpdatedAt string `json:"updated_at"`
15-
ForceChange bool `json:"forcechange" pg:"forceChange"`
10+
LastLoginAt string `json:"-" gorm:"-"`
11+
RememberToken string `json:"-" gorm:"-"`
12+
LastLoginIP string `json:"-" gorm:"-"`
13+
CreatedAt string `json:"-"`
14+
UpdatedAt string `json:"-"`
15+
ForceChange bool `json:"-" pg:"forceChange"`
1616
ObjectGUID string `json:"objectguid" pg:"objectguid"`
1717
AuthType string `json:"auth_type"`
1818
}

internal/liman/role_system.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,113 @@
11
package liman
2+
3+
import (
4+
"strings"
5+
6+
"github.com/gofiber/fiber/v2"
7+
"github.com/limanmys/render-engine/app/models"
8+
"github.com/limanmys/render-engine/internal/database"
9+
"github.com/limanmys/render-engine/pkg/helpers"
10+
)
11+
12+
func GetPermissions(user *models.User, extFilter string) ([]string, map[string]string, error) {
13+
roles, err := getRoleMaps(user)
14+
if err != nil {
15+
return nil, nil, err
16+
}
17+
18+
permissions := []string{}
19+
variables := make(map[string]string)
20+
for _, role := range roles {
21+
permission, variable, err := getPermissionsFromMorph(role, strings.ToLower(extFilter))
22+
if err != nil {
23+
return nil, nil, err
24+
}
25+
26+
permissions = append(permissions, permission...)
27+
28+
variables = helpers.MergeStringMaps(variables, variable)
29+
}
30+
31+
return permissions, variables, nil
32+
}
33+
34+
func GetObjectPermissions(user *models.User) ([]string, error) {
35+
roles, err := getRoleMaps(user)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
permissions := []string{}
41+
for _, role := range roles {
42+
permission, err := getObjectPermissionsFromMorph(role)
43+
if err != nil {
44+
return nil, err
45+
}
46+
47+
permissions = append(permissions, permission...)
48+
}
49+
50+
return permissions, nil
51+
}
52+
53+
func getPermissionsFromMorph(morphID string, extFilter string) ([]string, map[string]string, error) {
54+
permission := []*models.Permission{}
55+
56+
err := database.Connection().Find(&permission, "morph_id = ?", morphID).Error
57+
if err != nil {
58+
return nil, nil, fiber.NewError(fiber.StatusInternalServerError, "error while fetching the permissions")
59+
}
60+
61+
funcPerms := []string{}
62+
varPerms := make(map[string]string)
63+
64+
for _, item := range permission {
65+
if item.Type == "function" {
66+
if len(extFilter) > 0 {
67+
if extFilter == item.Value {
68+
funcPerms = append(funcPerms, item.Extra)
69+
}
70+
} else {
71+
funcPerms = append(funcPerms, item.Extra)
72+
}
73+
}
74+
75+
if item.Type == "variable" {
76+
varPerms[item.Key] = item.Value
77+
}
78+
}
79+
80+
return funcPerms, varPerms, nil
81+
}
82+
83+
func getObjectPermissionsFromMorph(morphID string) ([]string, error) {
84+
permissions := []*models.Permission{}
85+
86+
err := database.Connection().Find(&permissions, "morph_id = ? AND NOT type = 'function'", morphID).Error
87+
if err != nil {
88+
return nil, err
89+
}
90+
91+
results := []string{}
92+
for _, permission := range permissions {
93+
results = append(results, permission.Value)
94+
}
95+
96+
return results, nil
97+
}
98+
99+
func getRoleMaps(user *models.User) ([]string, error) {
100+
roles := []*models.RoleUsers{}
101+
102+
err := database.Connection().Find(&roles, "user_id = ?", user.ID).Error
103+
if err != nil {
104+
return nil, fiber.NewError(fiber.StatusInternalServerError, "error while fetching the roles")
105+
}
106+
107+
roleID := []string{user.ID}
108+
for _, item := range roles {
109+
roleID = append(roleID, item.RoleID)
110+
}
111+
112+
return roleID, nil
113+
}

internal/sandbox/command_generator.go

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ package sandbox
33
import (
44
"fmt"
55
"io/ioutil"
6-
"os"
76
"strings"
87

98
"github.com/alessio/shellescape"
109
"github.com/bytedance/sonic"
1110
"github.com/gofiber/fiber/v2"
1211
"github.com/limanmys/render-engine/app/models"
12+
"github.com/limanmys/render-engine/internal/constants"
1313
"github.com/limanmys/render-engine/internal/liman"
1414
"github.com/limanmys/render-engine/pkg/helpers"
1515
"github.com/mervick/aes-everywhere/go/aes256"
@@ -19,20 +19,15 @@ func GenerateCommand(extension *models.Extension, credentials *models.Credential
1919
extension.Name = shellescape.StripUnsafe(extension.Name)
2020

2121
if !helpers.IsLetter(extension.Name) {
22-
return "", fiber.NewError(fiber.StatusUnprocessableEntity, "Extension names can only contains letters")
22+
return "", fiber.NewError(fiber.StatusUnprocessableEntity, "extension names can only contains letters")
2323
}
2424

25-
server, err := liman.GetServer(&models.Server{ID: params.Server})
25+
server, user, settings, err := getParams(extension, credentials, params)
2626
if err != nil {
2727
return "", err
2828
}
2929

30-
user, err := liman.GetUser(&models.User{ID: params.User})
31-
if err != nil {
32-
return "", err
33-
}
34-
35-
settings, err := liman.GetSettings(user, server, extension)
30+
permissions, variables, err := liman.GetPermissions(user, extension.Name)
3631
if err != nil {
3732
return "", err
3833
}
@@ -53,52 +48,76 @@ func GenerateCommand(extension *models.Extension, credentials *models.Credential
5348
settingsJson, _ := sonic.Marshal(settings)
5449
userJson, _ := sonic.Marshal(user)
5550
requestData, _ := sonic.Marshal(params.RequestData)
51+
permissionsJson, _ := sonic.Marshal(permissions)
52+
variablesJson, _ := sonic.Marshal(variables)
5653

5754
extensionData := map[string]string{
5855
"server": string(serverJson),
5956
"extension": string(extensionJson),
6057
"settings": string(settingsJson),
6158
"user": string(userJson),
59+
"permissions": string(permissionsJson),
60+
"variables": string(variablesJson),
61+
"requestData": string(requestData),
62+
"publicPath": fmt.Sprintf(constants.EXTENSION_PUBLIC_PATH, params.BaseURL, extension.ID),
63+
"functionsPath": fmt.Sprintf("%s/%s%s", constants.EXTENSIONS_PATH, strings.ToLower(extension.Name), constants.FUNCTIONS_FILE_PATH),
64+
"navigationRoute": fmt.Sprintf(constants.NAVIGATION_ROUTE, extension.ID, server.City, server.ID),
6265
"key_type": credentials.Type,
63-
"functionsPath": fmt.Sprintf("/liman/extensions/%s/views/functions.php", strings.ToLower(extension.Name)),
6466
"function": params.TargetFunction,
65-
"requestData": string(requestData),
6667
"license": licenceData,
67-
"apiRoute": "/extensionRun",
68-
"navigationRoute": fmt.Sprintf("/l/%s/%s/%s", extension.ID, server.City, server.ID),
6968
"token": params.Token,
7069
"locale": params.Locale,
7170
"log_id": "0000000", // TODO: add log handlers
7271
"ajax": "true",
73-
"publicPath": fmt.Sprintf("%s/eklenti/%s/public/", params.BaseURL, extension.ID),
74-
"permissions": "[]",
75-
"variables": "[]",
76-
// TODO: Add role system
72+
"apiRoute": "/extensionRun",
7773
}
7874

79-
secureKey, err := ioutil.ReadFile("/liman/keys/" + extension.ID)
75+
secureKey, err := ioutil.ReadFile(constants.KEYS_PATH + "/" + extension.ID)
8076
if err != nil {
81-
return "", fiber.NewError(fiber.StatusNotFound, "Cannot found extension key file")
77+
return "", fiber.NewError(fiber.StatusNotFound, "cannot found extension key file")
8278
}
8379

8480
extensionDataJson, _ := sonic.Marshal(extensionData)
8581
encryptedData := aes256.Encrypt(string(extensionDataJson), string(secureKey))
8682

87-
timeout := "30"
88-
if len(os.Getenv("EXTENSION_TIMEOUT")) > 0 {
89-
timeout = os.Getenv("EXTENSION_TIMEOUT")
90-
}
83+
// TODO: extJsonfile
84+
// TODO: required param tester
85+
// TODO: targetFunction and permission match check
86+
// TODO: so file handler
9187

9288
command := fmt.Sprintf(
9389
"runuser %s -c 'timeout %s /usr/bin/php -d display_errors=on %s %s %s'",
9490
strings.Replace(extension.ID, "-", "", -1),
95-
timeout,
96-
"/liman/sandbox/php/index.php",
97-
"/liman/keys/"+extension.ID,
91+
helpers.Env("EXTENSION_TIMEOUT", "30"),
92+
constants.SANDBOX_PATH,
93+
constants.KEYS_PATH+"/"+extension.ID,
9894
encryptedData,
9995
)
10096

10197
// TODO: complete the command generator
10298

10399
return command, nil
104100
}
101+
102+
func getParams(
103+
extension *models.Extension,
104+
credentials *models.Credentials,
105+
params *models.CommandParams,
106+
) (*models.Server, *models.User, map[string]string, error) {
107+
server, err := liman.GetServer(&models.Server{ID: params.Server})
108+
if err != nil {
109+
return nil, nil, nil, err
110+
}
111+
112+
user, err := liman.GetUser(&models.User{ID: params.User})
113+
if err != nil {
114+
return nil, nil, nil, err
115+
}
116+
117+
settings, err := liman.GetSettings(user, server, extension)
118+
if err != nil {
119+
return nil, nil, nil, err
120+
}
121+
122+
return server, user, settings, nil
123+
}

0 commit comments

Comments
 (0)