Add escaping

This commit is contained in:
Arkadiy Tetelman authored and Arkadiy Tetelman committed 2026-06-12 16:35:36 -07:00
1 parent 1a894bc290
commit 0e1bc2418e
3 files changed
+58 -14

No files matched your search

+13
View File
@@ -0,0 +1,13 @@
syntax = "proto2";
package escaping;
option java_package = "a\"b\\c";
option go_package = "./;escaping";
message M {
reserved "ev\"il";
optional string note = 1 [default = "evil\";\n}\nmessage Injected {\n string pwned = 1;\n}\n//"];
optional bytes blob = 2 [default = "A\377\001hi"];
}
+40 -10
View File
@@ -40,6 +40,35 @@ func (pd *ProtoDefinition) write(s string) {
pd.builder.WriteString(s) pd.builder.WriteString(s)
} }
func escapeProtoString(s string) string {
var b strings.Builder
for i := 0; i < len(s); i++ {
switch c := s[i]; {
case c == '\\':
b.WriteString(`\\`)
case c == '"':
b.WriteString(`\"`)
case c == '\n':
b.WriteString(`\n`)
case c == '\r':
b.WriteString(`\r`)
case c == '\t':
b.WriteString(`\t`)
case c < 0x20 || c >= 0x7f:
fmt.Fprintf(&b, `\%03o`, c)
default:
b.WriteByte(c)
}
}
return b.String()
}
func (pd *ProtoDefinition) writeQuoted(s string) {
pd.write("\"")
pd.write(escapeProtoString(s))
pd.write("\"")
}
func (pd *ProtoDefinition) String() string { func (pd *ProtoDefinition) String() string {
return pd.builder.String() return pd.builder.String()
} }
@@ -143,7 +172,9 @@ func (pd *ProtoDefinition) writeField(field protoreflect.FieldDescriptor) {
pd.write(" [default = ") pd.write(" [default = ")
kind := field.Kind().String() kind := field.Kind().String()
if kind == "string" { if kind == "string" {
pd.write(fmt.Sprintf("\"%s\"", field.Default().String())) pd.writeQuoted(field.Default().String())
} else if kind == "bytes" {
pd.writeQuoted(string(field.Default().Bytes()))
} else if kind == "enum" { } else if kind == "enum" {
pd.write(string(field.DefaultEnumValue().Name())) pd.write(string(field.DefaultEnumValue().Name()))
} else { } else {
@@ -181,9 +212,9 @@ func (pd *ProtoDefinition) writeMessage(message protoreflect.MessageDescriptor)
for i := 0; i < message.ReservedNames().Len(); i++ { for i := 0; i < message.ReservedNames().Len(); i++ {
name := message.ReservedNames().Get(i) name := message.ReservedNames().Get(i)
pd.writeIndented("reserved \"") pd.writeIndented("reserved ")
pd.write(string(name)) pd.writeQuoted(string(name))
pd.write("\";\n") pd.write(";\n")
} }
for i := 0; i < message.ReservedRanges().Len(); i++ { for i := 0; i < message.ReservedRanges().Len(); i++ {
@@ -234,17 +265,16 @@ func (pd *ProtoDefinition) writeImport(fileImport protoreflect.FileImport) {
if fileImport.IsPublic { if fileImport.IsPublic {
pd.write("public ") pd.write("public ")
} }
pd.write("\"") pd.writeQuoted(fileImport.Path())
pd.write(fileImport.Path()) pd.write(";\n")
pd.write("\";\n")
} }
func (pd *ProtoDefinition) writeStringFileOptions(name string, value string) { func (pd *ProtoDefinition) writeStringFileOptions(name string, value string) {
pd.write("option ") pd.write("option ")
pd.write(name) pd.write(name)
pd.write(" = \"") pd.write(" = ")
pd.write(strings.ReplaceAll(value, "\\", "\\\\")) pd.writeQuoted(value)
pd.write("\";\n") pd.write(";\n")
} }
func (pd *ProtoDefinition) writeBoolFileOptions(name string, value bool) { func (pd *ProtoDefinition) writeBoolFileOptions(name string, value bool) {
+5 -4
View File
@@ -8,6 +8,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/descriptorpb"
) )
@@ -44,19 +45,19 @@ func convertProtoToFileDescriptor(filePath string) (*descriptorpb.FileDescriptor
func TestDefinitions(t *testing.T) { func TestDefinitions(t *testing.T) {
files, err := os.ReadDir(FIXTURES) files, err := os.ReadDir(FIXTURES)
assert.NoError(t, err) require.NoError(t, err)
for _, file := range files { for _, file := range files {
t.Run(file.Name(), func(t *testing.T) { t.Run(file.Name(), func(t *testing.T) {
filePath := path.Join(FIXTURES, file.Name()) filePath := path.Join(FIXTURES, file.Name())
descriptor, err := convertProtoToFileDescriptor(filePath) descriptor, err := convertProtoToFileDescriptor(filePath)
assert.NoError(t, err) require.NoError(t, err)
expected, err := os.ReadFile(filePath) expected, err := os.ReadFile(filePath)
assert.NoError(t, err) require.NoError(t, err)
actual, err := NewFromDescriptor(descriptor) actual, err := NewFromDescriptor(descriptor)
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, string(expected), actual.String()) assert.Equal(t, string(expected), actual.String())
}) })