fix(protocol): harden gateway contract validation
Verify Protocol / verify (push) Canceled after 0s
Verify Protocol / module (push) Successful in 2m12s

This commit is contained in:
sechmachine
2026-07-29 21:16:53 +07:00
parent 0ea21cd3f2
commit ebfe07376d
18 changed files with 337 additions and 44 deletions
+13 -7
View File
@@ -3,6 +3,7 @@ package protocol
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -12,7 +13,7 @@ import (
"time"
)
const SchemaSHA256 = "e35414af52d7a097dea05567fdab11f842a42e529fb6cbedd281c48dbf930b17"
const SchemaSHA256 = "e98c75ef81bbeac6be2b8f11202c1ffecec0aa515b48576a26756290e99d5dd8"
const ProtocolVersion = "1.0.0"
const CurrentWireVersion = "1"
const NMinus1WireVersion = "0"
@@ -968,6 +969,9 @@ func (v ChannelFrame) Validate() error {
if len(v.Payload) > 87384 {
violations = append(violations, FieldViolation{Field: "payload", Code: "max_length"})
}
if len(v.Payload) > 65536 {
violations = append(violations, FieldViolation{Field: "payload", Code: "max_bytes"})
}
if v.FragmentIndex >= v.FragmentCount {
violations = append(violations, FieldViolation{Field: "fragment_index", Code: "invalid_order"})
}
@@ -1010,9 +1014,6 @@ func DecodeChannelFrame(data []byte) (ChannelFrame, error) {
if raw, ok := fields["version"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
return value, ValidationError{Violations: []FieldViolation{{Field: "version", Code: "required"}}}
}
if raw, ok := fields["payload"]; ok && len(raw) > 65536 {
return value, ValidationError{Violations: []FieldViolation{{Field: "payload", Code: "max_bytes"}}}
}
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&value); err != nil {
@@ -2144,6 +2145,9 @@ func (v GatewayClipboardText) Validate() error {
if len(v.Text) > 65536 {
violations = append(violations, FieldViolation{Field: "text", Code: "max_length"})
}
if len(v.Text) > 65536 {
violations = append(violations, FieldViolation{Field: "text", Code: "max_bytes"})
}
if v.Encoding == "" {
violations = append(violations, FieldViolation{Field: "encoding", Code: "required"})
}
@@ -2159,6 +2163,11 @@ func (v GatewayClipboardText) Validate() error {
if len(v.LoopToken) > 128 {
violations = append(violations, FieldViolation{Field: "loop_token", Code: "max_length"})
}
if v.LoopToken != "" {
if _, err := base64.RawURLEncoding.Strict().DecodeString(v.LoopToken); err != nil {
violations = append(violations, FieldViolation{Field: "loop_token", Code: "invalid_format"})
}
}
if len(violations) > 0 {
return ValidationError{Violations: violations}
}
@@ -2186,9 +2195,6 @@ func DecodeGatewayClipboardText(data []byte) (GatewayClipboardText, error) {
if raw, ok := fields["text"]; !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
return value, ValidationError{Violations: []FieldViolation{{Field: "text", Code: "required"}}}
}
if raw, ok := fields["text"]; ok && len(raw) > 65536 {
return value, ValidationError{Violations: []FieldViolation{{Field: "text", Code: "max_bytes"}}}
}
decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&value); err != nil {