mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
146 lines
3.4 KiB
Go
146 lines
3.4 KiB
Go
// Pass 4 — security-sensitive manifest validation tests.
|
|||
|
|
//
|
||
|
|
// Locks in the regex / path-traversal / NUL-byte rules added in Pass 2 so
|
||
|
|
// regressions in Manifest.Validate are caught at CI time instead of via
|
||
|
|
// manual review.
|
||
|
|
package plugin
|
||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestPluginNameRegexp(t *testing.T) {
|
||
|
|
cases := []struct {
|
||
|
|
name string
|
||
|
|
ok bool
|
||
|
|
}{
|
||
|
|
{"hello", true},
|
||
|
|
{"game-detection", true},
|
||
|
|
{"a", true},
|
||
|
|
{"a1_b-c", true},
|
||
|
|
{"abcdefghijklmnopqrstuvwxyz0123456789_-abcdefghijklmnopqrstuvwxyz", true}, // 64 chars
|
||
|
|
{"abcdefghijklmnopqrstuvwxyz0123456789_-abcdefghijklmnopqrstuvwxyz0", false}, // 65 chars
|
||
|
|
{"", false},
|
||
|
|
{"Hello", false},
|
||
|
|
{"_leading", false},
|
||
|
|
{"-leading", false},
|
||
|
|
{"..", false},
|
||
|
|
{"a/b", false},
|
||
|
|
{"a.b", false},
|
||
|
|
{"a b", false},
|
||
|
|
{"a\x00b", false},
|
||
|
|
{"hello!", false},
|
||
|
|
}
|
||
|
|
for _, c := range cases {
|
||
|
|
got := pluginNameRegexp.MatchString(c.name)
|
||
|
|
if got != c.ok {
|
||
|
|
t.Errorf("pluginNameRegexp.MatchString(%q) = %v, want %v", c.name, got, c.ok)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestValidateRelativePath(t *testing.T) {
|
||
|
|
cases := []struct {
|
||
|
|
path string
|
||
|
|
ok bool
|
||
|
|
}{
|
||
|
|
{"a.wasm", true},
|
||
|
|
{"assets/index.html", true},
|
||
|
|
{"dir/sub/file.js", true},
|
||
|
|
{"hello.wasm", true},
|
||
|
|
// failures
|
||
|
|
{"", false},
|
||
|
|
{"/abs/path", false},
|
||
|
|
{"../escape", false},
|
||
|
|
{"./not-clean", false},
|
||
|
|
{"dir//double", false},
|
||
|
|
{"dir/", false},
|
||
|
|
{"dir\\win", false},
|
||
|
|
{"file\x00name", false},
|
||
|
|
{"..", false},
|
||
|
|
{".", false},
|
||
|
|
{"a/../b", false},
|
||
|
|
{"a/./b", false},
|
||
|
|
}
|
||
|
|
for _, c := range cases {
|
||
|
|
err := validateRelativePath(c.path)
|
||
|
|
got := err == nil
|
||
|
|
if got != c.ok {
|
||
|
|
t.Errorf("validateRelativePath(%q) ok=%v err=%v, want ok=%v", c.path, got, err, c.ok)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestManifestValidateRejectsBadName(t *testing.T) {
|
||
|
|
m := &Manifest{
|
||
|
|
Name: "Bad Name",
|
||
|
|
Version: "0.1.0",
|
||
|
|
Entrypoint: "hello.wasm",
|
||
|
|
}
|
||
|
|
if err := m.Validate(); err == nil {
|
||
|
|
t.Fatal("expected validation failure for invalid name")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestManifestValidateRejectsBadAsset(t *testing.T) {
|
||
|
|
m := &Manifest{
|
||
|
|
Name: "hello",
|
||
|
|
Version: "0.1.0",
|
||
|
|
Entrypoint: "hello.wasm",
|
||
|
|
UI: UISpec{
|
||
|
|
Tabs: []UITab{
|
||
|
|
{ID: "main", Asset: "../../../etc/passwd"},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
if err := m.Validate(); err == nil {
|
||
|
|
t.Fatal("expected validation failure for traversal asset")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestManifestValidateRejectsAbsoluteEntrypoint(t *testing.T) {
|
||
|
|
m := &Manifest{
|
||
|
|
Name: "hello",
|
||
|
|
Version: "0.1.0",
|
||
|
|
Entrypoint: "/etc/passwd.wasm",
|
||
|
|
}
|
||
|
|
if err := m.Validate(); err == nil {
|
||
|
|
t.Fatal("expected validation failure for absolute entrypoint")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestManifestValidateAcceptsMinimal(t *testing.T) {
|
||
|
|
m := &Manifest{
|
||
|
|
Name: "hello",
|
||
|
|
Version: "0.1.0",
|
||
|
|
Entrypoint: "hello.wasm",
|
||
|
|
}
|
||
|
|
if err := m.Validate(); err != nil {
|
||
|
|
t.Fatalf("expected minimal manifest to validate, got: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestManifestValidateRejectsOversizedVersion(t *testing.T) {
|
||
|
|
m := &Manifest{
|
||
|
|
Name: "hello",
|
||
|
|
Version: strings.Repeat("v", 65),
|
||
|
|
Entrypoint: "hello.wasm",
|
||
|
|
}
|
||
|
|
if err := m.Validate(); err == nil {
|
||
|
|
t.Fatal("expected validation failure for oversized version")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestManifestValidateRejectsUnknownPermission(t *testing.T) {
|
||
|
|
m := &Manifest{
|
||
|
|
Name: "hello",
|
||
|
|
Version: "0.1.0",
|
||
|
|
Entrypoint: "hello.wasm",
|
||
|
|
Permissions: []string{"commands", "filesystem"},
|
||
|
|
}
|
||
|
|
if err := m.Validate(); err == nil {
|
||
|
|
t.Fatal("expected validation failure for unknown permission")
|
||
|
|
}
|
||
|
|
}
|