mirror of
https://github.com/versity/versitygw.git
synced 2026-04-11 16:46:55 +00:00
170 lines
4.5 KiB
Go
170 lines
4.5 KiB
Go
package command
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
CURL = "curl"
|
|
OPENSSL = "openssl"
|
|
)
|
|
|
|
const (
|
|
UnsignedPayload = "UNSIGNED-PAYLOAD"
|
|
StreamingAWS4HMACSHA256Payload = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"
|
|
StreamingAWS4HMACSHA256PayloadTrailer = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER"
|
|
StreamingUnsignedPayloadTrailer = "STREAMING-UNSIGNED-PAYLOAD-TRAILER"
|
|
StreamingAWS4ECDSAP256SHA256Payload = "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD"
|
|
StreamingAWS4ECDSAP256SHA256PayloadTrailer = "STREAMING-AWS4-ECDSA-P256-SHA256-PAYLOAD-TRAILER"
|
|
)
|
|
|
|
type PayloadType string
|
|
|
|
const (
|
|
ChecksumCRC32 = "crc32"
|
|
ChecksumCRC32C = "crc32c"
|
|
ChecksumCRC64NVME = "crc64nvme"
|
|
ChecksumSHA1 = "sha1"
|
|
ChecksumSHA256 = "sha256"
|
|
)
|
|
|
|
const SHA256HashZeroBytes = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
|
|
type HeaderValue struct {
|
|
Key string
|
|
Value string
|
|
Signed bool
|
|
}
|
|
|
|
type S3RequestConfigData struct {
|
|
Client string
|
|
Method string
|
|
Url string
|
|
BucketName string
|
|
ObjectKey string
|
|
Query string
|
|
AwsRegion string
|
|
AwsAccessKeyId string
|
|
AwsSecretAccessKey string
|
|
ServiceName string
|
|
SignedParams map[string]string
|
|
UnsignedParams map[string]string
|
|
PayloadFile string
|
|
IncorrectSignature bool
|
|
AuthorizationHeaderMalformed bool
|
|
AuthorizationScheme string
|
|
IncorrectCredential string
|
|
IncorrectYearMonthDay bool
|
|
InvalidYearMonthDay bool
|
|
Payload string
|
|
ContentMD5 bool
|
|
IncorrectContentMD5 bool
|
|
CustomContentMD5 string
|
|
MissingHostParam bool
|
|
FilePath string
|
|
CustomHostParam string
|
|
CustomHostParamSet bool
|
|
PayloadType string
|
|
ChunkSize int
|
|
ChecksumType string
|
|
OmitPayloadTrailer bool
|
|
OmitPayloadTrailerKey bool
|
|
OmitContentLength bool
|
|
OmitSHA256Hash bool
|
|
CustomSHA256Hash string
|
|
OmitDate bool
|
|
CustomDate string
|
|
WriteXMLPayloadToFile string
|
|
}
|
|
|
|
type S3RequestBuilder struct {
|
|
Config *S3RequestConfigData
|
|
}
|
|
|
|
func (s *S3RequestBuilder) OpenSSLCommand() error {
|
|
openSSLCommand := &OpenSSLCommand{
|
|
S3Request: &S3Request{
|
|
Config: s.Config,
|
|
},
|
|
}
|
|
if err := s.RenderCommand(openSSLCommand); err != nil {
|
|
return fmt.Errorf("error rendering OpenSSL command: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *S3RequestBuilder) CurlShellCommand() (string, error) {
|
|
curlCommand := &CurlCommand{
|
|
S3Request: &S3Request{
|
|
Config: s.Config,
|
|
},
|
|
}
|
|
if err := s.RenderCommand(curlCommand); err != nil {
|
|
return "", fmt.Errorf("error rendering curl command: %w", err)
|
|
}
|
|
return curlCommand.String(), nil
|
|
}
|
|
|
|
func (s *S3RequestBuilder) RenderCommand(renderer Renderer) error {
|
|
renderer.CalculateDateTimeParams()
|
|
if err := renderer.DeriveHost(); err != nil {
|
|
return fmt.Errorf("error deriving host: %w", err)
|
|
}
|
|
renderer.DeriveBucketAndKeyPath()
|
|
if err := renderer.PerformPayloadCalculations(); err != nil {
|
|
return fmt.Errorf("error performing payload calculations: %w", err)
|
|
}
|
|
if err := renderer.DeriveHeaderValues(); err != nil {
|
|
return fmt.Errorf("error deriving header values: %w", err)
|
|
}
|
|
if err := renderer.CalculateSignature(); err != nil {
|
|
return fmt.Errorf("error calculating signature: %w", err)
|
|
}
|
|
if err := renderer.Render(); err != nil {
|
|
return fmt.Errorf("error rendering command: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func encodeS3Key(key string) string {
|
|
parts := strings.Split(key, "/")
|
|
for i, p := range parts {
|
|
parts[i] = awsEscapePath(p)
|
|
}
|
|
return strings.Join(parts, "/")
|
|
}
|
|
|
|
func awsEscapePath(key string) string {
|
|
var b strings.Builder
|
|
b.Grow(len(key))
|
|
for i := 0; i < len(key); i++ {
|
|
c := key[i]
|
|
if (c >= 'A' && c <= 'Z') ||
|
|
(c >= 'a' && c <= 'z') ||
|
|
(c >= '0' && c <= '9') ||
|
|
c == '-' || c == '_' || c == '.' || c == '~' || c == '/' {
|
|
b.WriteByte(c)
|
|
continue
|
|
}
|
|
fmt.Fprintf(&b, "%%%02X", c)
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
func modifyHash(md5Hash []byte) {
|
|
if md5Hash[0] == 'a' {
|
|
md5Hash[0] = 'A'
|
|
} else {
|
|
md5Hash[0] = 'a'
|
|
}
|
|
}
|
|
|
|
func hmacSHA256(key []byte, data string) []byte {
|
|
h := hmac.New(sha256.New, key)
|
|
h.Write([]byte(data))
|
|
return h.Sum(nil)
|
|
}
|