Files
summercms/modules/cabana/schema.go

67 lines
1.7 KiB
Go

package cabana
import (
"bytes"
"fmt"
"io/fs"
"path"
"strings"
"github.com/goccy/go-yaml"
)
func decodeStrict(raw []byte, dest any) error {
dec := yaml.NewDecoder(bytes.NewReader(raw), yaml.DisallowUnknownField())
if err := dec.Decode(dest); err != nil {
return err
}
return nil
}
// decodeStrictOrdered is decodeStrict with every nested mapping kept as an
// ordered yaml.MapSlice, so a file that is decoded, re-marshalled per entry and
// decoded again keeps its key order at any depth and any indentation.
func decodeStrictOrdered(raw []byte, dest any) error {
dec := yaml.NewDecoder(bytes.NewReader(raw), yaml.DisallowUnknownField(), yaml.UseOrderedMap())
return dec.Decode(dest)
}
func readAsset(fsys fs.FS, name string) ([]byte, error) {
name = path.Clean(name)
if name == "." || strings.HasPrefix(name, "..") || strings.Contains(name, "..") {
return nil, fmt.Errorf("path escapes the plugin")
}
return fs.ReadFile(fsys, name)
}
func assetPath(pluginID, ref string) (string, error) {
ref = strings.TrimSpace(ref)
ref = strings.TrimPrefix(ref, "~/")
prefix := "plugins/" + strings.ReplaceAll(pluginID, ".", "/") + "/"
ref = strings.TrimPrefix(ref, prefix)
ref = path.Clean(ref)
if ref == "." || strings.HasPrefix(ref, "..") || strings.Contains(ref, "..") {
return "", fmt.Errorf("list path escapes the plugin")
}
return ref, nil
}
func identifier(s string) bool {
if s == "" {
return false
}
for i, r := range s {
switch {
case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r == '_':
case i > 0 && r >= '0' && r <= '9':
default:
return false
}
}
return true
}
func bootErr(pluginID, controllerID, file string, err error) error {
return fmt.Errorf("cabana: admin schema %s/%s/%s: %w", pluginID, controllerID, file, err)
}