feat(plugin): add SCUM ownership migration foundation
This commit is contained in:
@@ -312,10 +312,20 @@ type GamePluginPage struct {
|
||||
Key string
|
||||
Title string
|
||||
Path string
|
||||
Bundle PluginPageBundle
|
||||
Permissions []string
|
||||
BridgeActions []string
|
||||
}
|
||||
|
||||
// PluginPageBundle identifies an installed plugin-owned page module. The host
|
||||
// validates this declaration before loading a bundle and never selects a game
|
||||
// page by plugin ID.
|
||||
type PluginPageBundle struct {
|
||||
Key string
|
||||
Version string
|
||||
IntegritySHA256 string
|
||||
}
|
||||
|
||||
// PluginFileWorkspace is a bounded, logical catalog for a plugin-owned files
|
||||
// workbench. Keys are logical identifiers, never host paths.
|
||||
type PluginFileWorkspace struct {
|
||||
|
||||
@@ -179,6 +179,9 @@ type GamePluginPageBody struct {
|
||||
Key string `json:"key"`
|
||||
Title string `json:"title"`
|
||||
Path string `json:"path"`
|
||||
BundleKey string `json:"bundleKey"`
|
||||
BundleVersion string `json:"bundleVersion"`
|
||||
BundleIntegritySHA256 string `json:"bundleIntegritySha256"`
|
||||
Permissions []string `json:"permissions,omitempty"`
|
||||
BridgeActions []string `json:"bridgeActions,omitempty"`
|
||||
}
|
||||
@@ -1880,6 +1883,7 @@ func pagesToDomain(pages []GamePluginPageBody) []domain.GamePluginPage {
|
||||
Key: page.Key,
|
||||
Title: page.Title,
|
||||
Path: page.Path,
|
||||
Bundle: domain.PluginPageBundle{Key: page.BundleKey, Version: page.BundleVersion, IntegritySHA256: page.BundleIntegritySHA256},
|
||||
Permissions: domain.CopyStringSlice(page.Permissions),
|
||||
BridgeActions: domain.CopyStringSlice(page.BridgeActions),
|
||||
}
|
||||
@@ -1897,6 +1901,9 @@ func pagesFromDomain(pages []domain.GamePluginPage) []GamePluginPageBody {
|
||||
Key: page.Key,
|
||||
Title: page.Title,
|
||||
Path: page.Path,
|
||||
BundleKey: page.Bundle.Key,
|
||||
BundleVersion: page.Bundle.Version,
|
||||
BundleIntegritySHA256: page.Bundle.IntegritySHA256,
|
||||
Permissions: domain.CopyStringSlice(page.Permissions),
|
||||
BridgeActions: domain.CopyStringSlice(page.BridgeActions),
|
||||
}
|
||||
|
||||
@@ -1397,6 +1397,12 @@ func validatePluginPages(pages []domain.GamePluginPage) []string {
|
||||
if !validPluginPagePath(page.Path) {
|
||||
violations = append(violations, prefix+".path is invalid")
|
||||
}
|
||||
if page.Bundle.Key != "" || page.Bundle.Version != "" || page.Bundle.IntegritySHA256 != "" {
|
||||
violations = appendRequired(violations, prefix+".bundle.key", page.Bundle.Key)
|
||||
violations = appendRequired(violations, prefix+".bundle.version", page.Bundle.Version)
|
||||
violations = appendRequired(violations, prefix+".bundle.integritySha256", page.Bundle.IntegritySHA256)
|
||||
if !validDistributionLogicalKey(page.Bundle.Key) || !validPluginPageBundleVersion(page.Bundle.Version) || !validPluginPageBundleIntegrity(page.Bundle.IntegritySHA256) { violations = append(violations, prefix+".bundle is invalid") }
|
||||
}
|
||||
if page.Key != "" {
|
||||
if _, exists := seenKeys[page.Key]; exists {
|
||||
violations = append(violations, prefix+".key duplicates another page")
|
||||
@@ -1414,6 +1420,18 @@ func validatePluginPages(pages []domain.GamePluginPage) []string {
|
||||
return violations
|
||||
}
|
||||
|
||||
func validPluginPageBundleVersion(value string) bool {
|
||||
if len(value) == 0 || len(value) > 80 { return false }
|
||||
for _, item := range value { if !(item >= 'a' && item <= 'z' || item >= 'A' && item <= 'Z' || item >= '0' && item <= '9' || item == '.' || item == '_' || item == '-') { return false } }
|
||||
return true
|
||||
}
|
||||
|
||||
func validPluginPageBundleIntegrity(value string) bool {
|
||||
if len(value) != len("sha256:")+64 || !strings.HasPrefix(value, "sha256:") { return false }
|
||||
for _, item := range value[len("sha256:"):] { if !(item >= 'a' && item <= 'f' || item >= '0' && item <= '9') { return false } }
|
||||
return true
|
||||
}
|
||||
|
||||
func validatePluginFileWorkspace(prefix string, workspace domain.PluginFileWorkspace) []string {
|
||||
if workspace.DefaultDirectoryKey == "" && len(workspace.Directories) == 0 && len(workspace.Files) == 0 && len(workspace.ConfigFields) == 0 {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user