From dd84b9d64fb98746a230cd24233ff50a562c39c9 Mon Sep 17 00:00:00 2001 From: 简律纯 Date: Fri, 28 Apr 2023 01:36:44 +0800 Subject: --- cli/internal/encoding/gitoutput/validators.go | 148 ++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 cli/internal/encoding/gitoutput/validators.go (limited to 'cli/internal/encoding/gitoutput/validators.go') diff --git a/cli/internal/encoding/gitoutput/validators.go b/cli/internal/encoding/gitoutput/validators.go new file mode 100644 index 0000000..e13c2d5 --- /dev/null +++ b/cli/internal/encoding/gitoutput/validators.go @@ -0,0 +1,148 @@ +package gitoutput + +import "bytes" + +var _allowedObjectType = []byte(" blob tree commit ") +var _allowedStatusChars = []byte(" MTADRCU?!") + +// checkValid provides a uniform interface for calling `gitoutput` validators. +func checkValid(fieldType Field, value []byte) error { + switch fieldType { + case ObjectMode: + return checkObjectMode(value) + case ObjectType: + return checkObjectType(value) + case ObjectName: + return CheckObjectName(value) + case ObjectStage: + return checkObjectStage(value) + case StatusX: + return checkStatusX(value) + case StatusY: + return checkStatusY(value) + case Path: + return checkPath(value) + default: + return ErrUnknownField + } +} + +// checkObjectMode asserts that a byte slice is a six digit octal string (100644). +// It does not attempt to ensure that the values in particular positions are reasonable. +func checkObjectMode(value []byte) error { + if len(value) != 6 { + return ErrInvalidObjectMode + } + + // 0-7 are 0x30 - 0x37 + for _, currentByte := range value { + if (currentByte ^ 0x30) > 7 { + return ErrInvalidObjectMode + } + } + + // length of 6, 0-7 + return nil +} + +// checkObjectType asserts that a byte slice is a valid possibility (blob, tree, commit). +func checkObjectType(value []byte) error { + typeLength := len(value) + // Based upon: + // min(len("blob"), len("tree"), len("commit")) + // max(len("blob"), len("tree"), len("commit")) + if typeLength < 4 || typeLength > 6 { + return ErrInvalidObjectType + } + + // Because of the space separator there is no way to pass in a space. + // We use that trick to enable fast lookups in _allowedObjectType. + index := bytes.Index(_allowedObjectType, value) + + // Impossible to match at 0, not found is -1. + if index < 1 { + return ErrInvalidObjectType + } + + // Followed by a space. + if _allowedObjectType[index-1] != byte(_space) { + return ErrInvalidObjectType + } + + // Preceded by a space. + if _allowedObjectType[index+typeLength] != byte(_space) { + return ErrInvalidObjectType + } + return nil +} + +// CheckObjectName asserts that a byte slice looks like a SHA hash. +func CheckObjectName(value []byte) error { + if len(value) != 40 { + return ErrInvalidObjectName + } + + // 0-9 are 0x30 - 0x39 + // a-f are 0x61 - 0x66 + for _, currentByte := range value { + isNumber := (currentByte ^ 0x30) < 10 + numericAlpha := (currentByte ^ 0x60) + isAlpha := (numericAlpha < 7) && (numericAlpha > 0) + if !(isNumber || isAlpha) { + return ErrInvalidObjectName + } + } + + // length of 40, hex + return nil +} + +// checkObjectStage asserts that a byte slice is a valid possibility (0-3). +func checkObjectStage(value []byte) error { + // 0-3 are 0x30 - 0x33 + if len(value) != 1 { + return ErrInvalidObjectStage + } + + currentByte := value[0] + if (currentByte ^ 0x30) >= 4 { + return ErrInvalidObjectStage + } + + return nil +} + +// checkStatusX asserts that a byte slice is a valid possibility (" MTADRCU?!"). +func checkStatusX(value []byte) error { + if len(value) != 1 { + return ErrInvalidObjectStatusX + } + + index := bytes.Index(_allowedStatusChars, value) + if index == -1 { + return ErrInvalidObjectStatusX + } + return nil +} + +// checkStatusY asserts that a byte slice is a valid possibility (" MTADRCU?!"). +func checkStatusY(value []byte) error { + if len(value) != 1 { + return ErrInvalidObjectStatusY + } + + index := bytes.Index(_allowedStatusChars, value) + if index == -1 { + return ErrInvalidObjectStatusY + } + return nil +} + +// checkPath asserts that a byte slice is non-empty. +func checkPath(value []byte) error { + // Exists at all. This is best effort as trying to be fully-compatible is silly. + if len(value) == 0 { + return ErrInvalidPath + } + return nil +} -- cgit v1.2.3-70-g09d2