Skip to content

Commit

Permalink
Merge pull request #769 from trheyi/main
Browse files Browse the repository at this point in the history
Securely update hidden props in the DSL that are only visible to the backend
  • Loading branch information
trheyi authored Nov 2, 2024
2 parents 1cdf1f6 + a4bb440 commit 6263120
Show file tree
Hide file tree
Showing 22 changed files with 278 additions and 24 deletions.
2 changes: 1 addition & 1 deletion utils/datetime_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package utils
package utils_test

import (
"testing"
Expand Down
11 changes: 11 additions & 0 deletions utils/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/yaoapp/yao/utils/fmt"
"github.com/yaoapp/yao/utils/json"
"github.com/yaoapp/yao/utils/str"
"github.com/yaoapp/yao/utils/throw"
"github.com/yaoapp/yao/utils/tree"
"github.com/yaoapp/yao/utils/url"
)
Expand All @@ -15,6 +16,16 @@ func Init() {
process.Alias("xiang.helper.Captcha", "yao.utils.Captcha") // deprecated
process.Alias("xiang.helper.CaptchaValidate", "yao.utils.CaptchaValidate") // deprecated

// ****************************************
// * Processes Version 0.10.4+
// ****************************************
process.Register("utils.throw.Forbidden", throw.Forbidden)
process.Register("utils.throw.Unauthorized", throw.Unauthorized)
process.Register("utils.throw.NotFound", throw.NotFound)
process.Register("utils.throw.BadRequest", throw.BadRequest)
process.Register("utils.throw.InternalError", throw.InternalError)
process.Register("utils.throw.Exception", throw.Exception)

// ****************************************
// * Migrate Processes Version 0.10.2+
// ****************************************
Expand Down
2 changes: 1 addition & 1 deletion utils/str_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package utils
package utils_test

import (
"fmt"
Expand Down
50 changes: 50 additions & 0 deletions utils/throw/throw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package throw

import (
"github.com/yaoapp/gou/process"
"github.com/yaoapp/kun/exception"
)

// Unauthorized throw a unauthorized exception
func Unauthorized(process *process.Process) interface{} {
message := process.ArgsString(0, "Authentication required")
exception.New(message, 401).Throw()
return nil
}

// Forbidden throw a forbidden exception
func Forbidden(process *process.Process) interface{} {
message := process.ArgsString(0, "Access denied")
exception.New(message, 403).Throw()
return nil
}

// NotFound throw a not found exception
func NotFound(process *process.Process) interface{} {
message := process.ArgsString(0, "Resource not found")
exception.New(message, 404).Throw()
return nil
}

// BadRequest throw a bad request exception
func BadRequest(process *process.Process) interface{} {
message := process.ArgsString(0, "Bad Request")
exception.New(message, 400).Throw()
return nil
}

// InternalError throw a internal error exception
func InternalError(process *process.Process) interface{} {
message := process.ArgsString(0, "Internal Error")
exception.New(message, 500).Throw()
return nil
}

// Exception throw a exception
func Exception(process *process.Process) interface{} {
process.ValidateArgNums(2)
message := process.ArgsString(0)
code := process.ArgsInt(1)
exception.New(message, code).Throw()
return nil
}
57 changes: 57 additions & 0 deletions utils/throw_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package utils_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou/process"
"github.com/yaoapp/yao/utils"
)

func TestProcessUnauthorized(t *testing.T) {
utils.Init()
proc := process.New("utils.throw.Unauthorized", "Authentication required")
err := proc.Execute()
assert.NotNil(t, err)
assert.Equal(t, "Exception|401: Authentication required", err.Error())
}

func TestProcessForbidden(t *testing.T) {
utils.Init()
proc := process.New("utils.throw.Forbidden", "Access denied")
err := proc.Execute()
assert.NotNil(t, err)
assert.Equal(t, "Exception|403: Access denied", err.Error())
}

func TestProcessNotFound(t *testing.T) {
utils.Init()
proc := process.New("utils.throw.NotFound", "Resource not found")
err := proc.Execute()
assert.NotNil(t, err)
assert.Equal(t, "Exception|404: Resource not found", err.Error())
}

func TestProcessBadRequest(t *testing.T) {
utils.Init()
proc := process.New("utils.throw.BadRequest", "Bad Request")
err := proc.Execute()
assert.NotNil(t, err)
assert.Equal(t, "Exception|400: Bad Request", err.Error())
}

func TestProcessInternalError(t *testing.T) {
utils.Init()
proc := process.New("utils.throw.InternalError", "Internal Error")
err := proc.Execute()
assert.NotNil(t, err)
assert.Equal(t, "Exception|500: Internal Error", err.Error())
}

func TestProcessException(t *testing.T) {
utils.Init()
proc := process.New("utils.throw.Exception", "I'm a teapot", 418)
err := proc.Execute()
assert.NotNil(t, err)
assert.Equal(t, "Exception|418: I'm a teapot", err.Error())
}
2 changes: 1 addition & 1 deletion utils/tree_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package utils
package utils_test

import (
"testing"
Expand Down
9 changes: 5 additions & 4 deletions utils/url_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package utils
package utils_test

import (
"net/url"
Expand All @@ -7,10 +7,11 @@ import (
"github.com/stretchr/testify/assert"
"github.com/yaoapp/gou/process"
"github.com/yaoapp/gou/types"
"github.com/yaoapp/yao/utils"
)

func TestProcessParseQuery(t *testing.T) {
Init()
utils.Init()
args := []interface{}{"a=1&b=2&c=3&c=4"}
result, err := process.New("utils.url.ParseQuery", args...).Exec()
if err != nil {
Expand All @@ -23,7 +24,7 @@ func TestProcessParseQuery(t *testing.T) {
}

func TestProcessParseURL(t *testing.T) {
Init()
utils.Init()
args := []interface{}{"http://www.google.com:8080/search?q=dotnet"}
result, err := process.New("utils.url.ParseURL", args...).Exec()
if err != nil {
Expand All @@ -40,7 +41,7 @@ func TestProcessParseURL(t *testing.T) {
}

func TestProcessQueryParam(t *testing.T) {
Init()
utils.Init()
args := []interface{}{
map[string]interface{}{
"where.name.eq": "yao",
Expand Down
5 changes: 5 additions & 0 deletions widgets/chart/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func (dsl *DSL) mapping() error {
if dsl.Fields.Filter != nil && dsl.Layout.Filter != nil && dsl.Layout.Filter.Columns != nil {
for _, inst := range dsl.Layout.Filter.Columns {
if filter, has := dsl.Fields.Filter[inst.Name]; has {
// Add the default value, and parse the backend only props
filter.Parse()

// Mapping ID
dsl.Mapping.Filters[filter.ID] = inst.Name
Expand All @@ -79,6 +81,9 @@ func (dsl *DSL) mapping() error {
for _, inst := range dsl.Layout.Chart.Columns {
if field, has := dsl.Fields.Chart[inst.Name]; has {

// Add the default value, and parse the backend only props
field.Parse()

// Mapping ID
dsl.Mapping.Columns[field.ID] = inst.Name
dsl.Mapping.Columns[inst.Name] = field.ID
Expand Down
81 changes: 75 additions & 6 deletions widgets/component/component.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package component

import (
"strings"

jsoniter "github.com/json-iterator/go"
)

Expand All @@ -10,6 +12,35 @@ import (
// yao.component.ImageView
// yao.component.UploadEdit

// BackendOnlyProps The component’s properties include visibility for backend only
var BackendOnlyProps = map[string]map[string]map[string]interface{}{
"select": {
"query": {
"xProps": map[string]interface{}{
"$remote": map[string]interface{}{"process": "yao.component.GetOptions"},
},
},
},
"autocomplete": {"query": {
"xProps": map[string]interface{}{
"$remote": map[string]interface{}{"process": "yao.component.GetOptions"},
},
}},
}

// DefaultProps The default properties for the component
var DefaultProps = map[string]map[string]map[string]interface{}{
"upload": {"api": {"$api": map[string]interface{}{"process": "fs.data.Upload"}}},
"image": {"api": {"$api": map[string]interface{}{"process": "utils.throw.Forbidden"}}}, // Just generate an effective URL, no need to upload
}

// UploadComponents the components that need to upload files
var UploadComponents = map[string]bool{
"upload": true,
"wangeditor": true,
"image": true,
}

// Export processes
func Export() error {
exportProcess()
Expand All @@ -25,12 +56,7 @@ func (dsl DSL) MarshalJSON() ([]byte, error) {
func (dsl DSL) Map() map[string]interface{} {
res := map[string]interface{}{
"type": dsl.Type,
"props": map[string]interface{}(dsl.Props),
}

// Add Default Value for Upload api
if (dsl.Type == "Upload" || dsl.Type == "Image") && dsl.Props != nil && !dsl.Props.Has("api") {
res["props"].(map[string]interface{})["$api"] = map[string]interface{}{"process": "fs.data.Upload"}
"props": dsl.FontendProps(),
}

if dsl.HideLabel {
Expand All @@ -43,6 +69,49 @@ func (dsl DSL) Map() map[string]interface{} {
return res
}

// FontendProps filter backend only properties
func (dsl DSL) FontendProps() map[string]interface{} {
if dsl.Props == nil {
return map[string]interface{}{}
}

props := map[string]interface{}{}
t := strings.ToLower(dsl.Type)
for key, val := range dsl.Props {
if BackendOnlyProps[t] != nil && BackendOnlyProps[t][key] != nil {
continue
}
props[key] = val
}
return props
}

// Parse the component properties
func (dsl *DSL) Parse() {
t := strings.ToLower(dsl.Type)
// Check if the component has default props
if dsl.Props != nil && DefaultProps[t] != nil {
for key, val := range DefaultProps[t] {
if !dsl.Props.Has(key) {
for k, v := range val {
dsl.Props[k] = v
}
}
}
}

// Check if the component has backend only props
if dsl.Props != nil && BackendOnlyProps[t] != nil {
for key, val := range BackendOnlyProps[t] {
if dsl.Props.Has(key) {
for k, v := range val {
dsl.Props[k] = v
}
}
}
}
}

// Clone Component
func (dsl *DSL) Clone() *DSL {
new := DSL{
Expand Down
11 changes: 11 additions & 0 deletions widgets/component/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,24 @@ import (
"github.com/yaoapp/gou/process"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/utils"
)

// Export process
func exportProcess() {
process.Register("yao.component.getoptions", processGetOptions)
process.Register("yao.component.selectoptions", processSelectOptions)
}

// processGetOptions get options
func processGetOptions(process *process.Process) interface{} {
utils.Dump(process.Args)
return []map[string]interface{}{
{"label": "Option 1", "value": "1"},
{"label": "Option 2", "value": "2"},
}
}

func processSelectOptions(process *process.Process) interface{} {
process.ValidateArgNums(1)
query := process.ArgsMap(0, map[string]interface{}{})
Expand Down
Loading

0 comments on commit 6263120

Please sign in to comment.