Ship SCUM user SQL management page
This commit is contained in:
@@ -109,10 +109,14 @@ func validateRemoteAdapterInputs(field string, inputs map[string]string) []strin
|
||||
}
|
||||
var violations []string
|
||||
for key, value := range inputs {
|
||||
if !clientManagerIdentifierPattern.MatchString(key) || unsafeGameClientBridgePayloadKey(key) {
|
||||
if !clientManagerIdentifierPattern.MatchString(key) || unsafeRemoteAdapterInputKey(key) {
|
||||
violations = append(violations, field+" key is invalid or unsafe")
|
||||
}
|
||||
if len([]rune(value)) > 2048 {
|
||||
limit := 2048
|
||||
if remoteAdapterSQLInputKey(key) {
|
||||
limit = 16 * 1024
|
||||
}
|
||||
if len([]rune(value)) > limit {
|
||||
violations = append(violations, field+"."+key+" is too long")
|
||||
}
|
||||
for _, reason := range unsafePluginStringReasons(value) {
|
||||
@@ -121,3 +125,20 @@ func validateRemoteAdapterInputs(field string, inputs map[string]string) []strin
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
func unsafeRemoteAdapterInputKey(key string) bool {
|
||||
if remoteAdapterSQLInputKey(key) {
|
||||
return false
|
||||
}
|
||||
return unsafeGameClientBridgePayloadKey(key)
|
||||
}
|
||||
|
||||
func remoteAdapterSQLInputKey(key string) bool {
|
||||
normalized := strings.ToLower(strings.NewReplacer(".", "", "_", "", "-", "", ":", "", "/", "").Replace(key))
|
||||
switch normalized {
|
||||
case "sql", "sqltext", "sqlstatement", "sqlquery", "rawsql", "rawquery", "statement":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ func TestObservabilityValidatorsBoundMetricsBackupsAndRemoteTargets(t *testing.T
|
||||
if err := ValidateRemoteAdapterRequest(domain.RemoteAdapterRequest{ServerInstanceID: "server-1", DeclarationKey: "ftp", TargetKey: "tcp://host", Capability: "remote.ftp.read", IdempotencyKey: "request-1"}); err == nil {
|
||||
t.Fatal("expected unsafe remote target rejection")
|
||||
}
|
||||
if err := ValidateRemoteAdapterRequest(domain.RemoteAdapterRequest{ServerInstanceID: "server-1", DeclarationKey: "sqlite-db", TargetKey: "scum-db", Capability: domain.JobCapabilityRemoteRunDBSQLiteExecute, IdempotencyKey: "sql-execute-1", Inputs: map[string]string{"mode": "execute", "sqlText": "UPDATE prisoner SET stamina = 855 WHERE id = 'steam-123';"}}); err != nil {
|
||||
t.Fatalf("expected SQL text input to validate: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func floatPtr(value float64) *float64 { return &value }
|
||||
|
||||
@@ -21,7 +21,7 @@ const (
|
||||
maxPluginDescriptionLength = 240
|
||||
maxPluginPageTitleLength = 40
|
||||
maxPluginBridgePayloadKeys = 16
|
||||
maxPluginBridgePayloadSize = 4096
|
||||
maxPluginBridgePayloadSize = 16 * 1024
|
||||
maxProgressMessageLength = 256
|
||||
maxServerConfigContentSize = 64 * 1024
|
||||
maxJobExecutionContentSize = 64 * 1024
|
||||
@@ -971,7 +971,11 @@ func ValidatePluginBridgeExecuteRequest(request domain.PluginBridgeExecuteReques
|
||||
if strings.TrimSpace(key) == "" || strings.TrimSpace(key) != key || len([]rune(key)) > 80 {
|
||||
violations = append(violations, "payload key is invalid")
|
||||
}
|
||||
if len([]rune(value)) > 1024 {
|
||||
valueLimit := 1024
|
||||
if remoteAdapterSQLInputKey(strings.TrimPrefix(key, "input.")) {
|
||||
valueLimit = 16 * 1024
|
||||
}
|
||||
if len([]rune(value)) > valueLimit {
|
||||
violations = append(violations, "payload value is too long")
|
||||
}
|
||||
for _, reason := range unsafePluginStringReasons(key) {
|
||||
@@ -2053,12 +2057,14 @@ func validateRemoteAccess(field string, remote domain.GamePluginRemoteAccess, de
|
||||
violations = append(violations, field+".logTransfer requires remote.run.logs.transfer")
|
||||
}
|
||||
for _, engine := range remote.DatabaseEngines {
|
||||
required := domain.JobCapabilityRemoteRunDBMySQLQuery
|
||||
queryCapability := domain.JobCapabilityRemoteRunDBMySQLQuery
|
||||
executeCapability := domain.JobCapabilityRemoteRunDBMySQLExecute
|
||||
if engine == "sqlite" {
|
||||
required = domain.JobCapabilityRemoteRunDBSQLiteQuery
|
||||
queryCapability = domain.JobCapabilityRemoteRunDBSQLiteQuery
|
||||
executeCapability = domain.JobCapabilityRemoteRunDBSQLiteExecute
|
||||
}
|
||||
if !containsString(remote.RunCapabilities, required) {
|
||||
violations = append(violations, fmt.Sprintf("%s.databaseEngines requires %s", field, required))
|
||||
if !containsString(remote.RunCapabilities, queryCapability) && !containsString(remote.RunCapabilities, executeCapability) {
|
||||
violations = append(violations, fmt.Sprintf("%s.databaseEngines requires %s or %s", field, queryCapability, executeCapability))
|
||||
}
|
||||
}
|
||||
return violations
|
||||
@@ -2352,7 +2358,7 @@ func validPluginRunCapability(capability string) bool {
|
||||
domain.JobCapabilityRemoteRsyncRead, domain.JobCapabilityRemoteRsyncWrite,
|
||||
domain.JobCapabilityRemoteRunFilesRead, domain.JobCapabilityRemoteRunFilesWrite,
|
||||
domain.JobCapabilityRemoteRunProcessStart, domain.JobCapabilityRemoteRunProcessStop,
|
||||
domain.JobCapabilityRemoteRunDBMySQLQuery, domain.JobCapabilityRemoteRunDBSQLiteQuery,
|
||||
domain.JobCapabilityRemoteRunDBMySQLQuery, domain.JobCapabilityRemoteRunDBMySQLExecute, domain.JobCapabilityRemoteRunDBSQLiteQuery, domain.JobCapabilityRemoteRunDBSQLiteExecute,
|
||||
domain.JobCapabilityRemoteRunLogsTransfer, domain.JobCapabilityRemoteRunRCONCommand,
|
||||
domain.JobCapabilityRemoteRunProgram,
|
||||
domain.JobCapabilityRunSelfUpdate, domain.JobCapabilityDependenciesCheck, domain.JobCapabilityDependenciesInstall,
|
||||
@@ -2386,7 +2392,9 @@ func remoteCapabilityRequiresInputRef(capability string) bool {
|
||||
domain.JobCapabilityRemoteRsyncWrite,
|
||||
domain.JobCapabilityRemoteRunFilesWrite,
|
||||
domain.JobCapabilityRemoteRunDBMySQLQuery,
|
||||
domain.JobCapabilityRemoteRunDBMySQLExecute,
|
||||
domain.JobCapabilityRemoteRunDBSQLiteQuery,
|
||||
domain.JobCapabilityRemoteRunDBSQLiteExecute,
|
||||
domain.JobCapabilityRemoteRunRCONCommand, domain.JobCapabilityRemoteRunProgram:
|
||||
return true
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user