2021-11-13 02:13:48 +01:00
|
|
|
package http
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"net/http"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
|
|
|
|
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type AwsSigner struct {
|
|
|
|
|
creds *credentials.Credentials
|
|
|
|
|
signer *v4.Signer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type SignArguments struct {
|
|
|
|
|
Service string
|
|
|
|
|
Region string
|
|
|
|
|
Time time.Time
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewAwsSigner(awsId, awsSecretToken string) (*AwsSigner, error) {
|
|
|
|
|
if awsId == "" {
|
|
|
|
|
return nil, errors.New("empty id")
|
|
|
|
|
}
|
|
|
|
|
if awsSecretToken == "" {
|
|
|
|
|
return nil, errors.New("empty token")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
creds := credentials.NewStaticCredentials(awsId, awsSecretToken, "")
|
|
|
|
|
if creds == nil {
|
|
|
|
|
return nil, errors.New("couldn't create the credentials structure")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signer := v4.NewSigner(creds)
|
|
|
|
|
|
|
|
|
|
return &AwsSigner{creds: creds, signer: signer}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewAwsSignerFromEnv() (*AwsSigner, error) {
|
|
|
|
|
creds := credentials.NewEnvCredentials()
|
|
|
|
|
if creds == nil {
|
|
|
|
|
return nil, errors.New("couldn't create the credentials structure")
|
|
|
|
|
}
|
|
|
|
|
return &AwsSigner{creds: creds}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 21:44:58 +01:00
|
|
|
func NewAwsSignerFromFile() (*AwsSigner, error) {
|
|
|
|
|
creds := credentials.NewSharedCredentials("", "")
|
|
|
|
|
if creds == nil {
|
|
|
|
|
return nil, errors.New("couldn't create the credentials structure")
|
|
|
|
|
}
|
|
|
|
|
return &AwsSigner{creds: creds}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-13 02:13:48 +01:00
|
|
|
func (awsSigner *AwsSigner) SignHTTP(request *http.Request, args SignArguments) error {
|
|
|
|
|
awsSigner.prepareRequest(request)
|
|
|
|
|
var body *bytes.Reader
|
|
|
|
|
if request.Body != nil {
|
|
|
|
|
bodyBytes, err := ioutil.ReadAll(request.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
request.Body.Close()
|
|
|
|
|
body = bytes.NewReader(bodyBytes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err := awsSigner.signer.Sign(request, body, args.Service, args.Region, args.Time); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (awsSigner *AwsSigner) CalculateHTTPHeaders(request *http.Request, args SignArguments) (map[string]string, error) {
|
|
|
|
|
reqClone := request.Clone(context.Background())
|
|
|
|
|
awsSigner.prepareRequest(reqClone)
|
|
|
|
|
err := awsSigner.SignHTTP(reqClone, args)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
headers := make(map[string]string)
|
|
|
|
|
headers["X-Amz-Date"] = reqClone.Header.Get("X-Amz-Date")
|
|
|
|
|
headers["Authorization"] = reqClone.Header.Get("Authorization")
|
|
|
|
|
return headers, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (awsSigner *AwsSigner) prepareRequest(request *http.Request) {
|
|
|
|
|
request.Header.Del("Host")
|
|
|
|
|
}
|