package playback import ( "context" "errors" "fmt" "io" "net/http" "net/url" "strconv" "strings" "time" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/auth" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/detector" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/xmlutils" v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4" "github.com/aws/aws-sdk-go-v2/credentials" ) type ( httpBody []byte LoggedRequest struct { From string `json:"from"` URI string `json:"URI"` Method string `json:"method"` Payload httpBody `json:"payload,omitempty"` Response httpBody `json:"response,omitempty"` Query url.Values `json:"query"` Header http.Header `json:"headers"` } Credentials struct { AccessKey string SecretKey string } Settings struct { Endpoint string Creds Credentials Multiparts map[string]MultipartUpload Client *http.Client } ) func (h *httpBody) UnmarshalJSON(data []byte) error { unquoted, err := strconv.Unquote(string(data)) if err != nil { return fmt.Errorf("failed to unquote data: %w", err) } detect := detector.NewDetector(strings.NewReader(unquoted), xmlutils.DetectXML) dataType, err := detect.Detect() if err != nil { return fmt.Errorf("failed to detect data: %w", err) } reader := xmlutils.ChooseReader(dataType, detect.RestoredReader()) *h, err = io.ReadAll(reader) if err != nil { return fmt.Errorf("failed to unmarshal httpbody: %w", err) } return nil } // Sign replace Authorization header with new Access key id and Signature values. func Sign(ctx context.Context, r *http.Request, creds Credentials) error { credProvider := credentials.NewStaticCredentialsProvider(creds.AccessKey, creds.SecretKey, "") awsCred, err := credProvider.Retrieve(ctx) if err != nil { return err } authHdr := r.Header.Get(auth.AuthorizationHdr) authInfo, err := parseAuthHeader(authHdr) if err != nil { return err } newHeader := strings.Replace(authHdr, authInfo["access_key_id"], creds.AccessKey, 1) r.Header.Set(auth.AuthorizationHdr, newHeader) signer := v4.NewSigner() signatureDateTimeStr := r.Header.Get(api.AmzDate) signatureDateTime, err := time.Parse("20060102T150405Z", signatureDateTimeStr) if err != nil { return err } return signer.SignHTTP(ctx, awsCred, r, r.Header.Get(api.AmzContentSha256), authInfo["service"], authInfo["region"], signatureDateTime) } func parseAuthHeader(authHeader string) (map[string]string, error) { authInfo := auth.NewRegexpMatcher(auth.AuthorizationFieldRegexp).GetSubmatches(authHeader) if len(authInfo) == 0 { return nil, errors.New("no matches found") } return authInfo, nil }