mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 13:55:24 +00:00
* setup claude * migrate to using errkit * fix unused imports + lint errors * update settings.json * fix url encoding issue * fix lint error * fix the path fuzzing component * fix lint error
138 lines
3.5 KiB
Go
138 lines
3.5 KiB
Go
package signer
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
v4 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
|
|
awsconfig "github.com/aws/aws-sdk-go-v2/config"
|
|
"github.com/aws/aws-sdk-go-v2/credentials"
|
|
"github.com/projectdiscovery/gologger"
|
|
"github.com/projectdiscovery/utils/errkit"
|
|
)
|
|
|
|
const defaultEmptyPayloadHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
|
|
// AWSOptions
|
|
type AWSOptions struct {
|
|
AwsID string
|
|
AwsSecretToken string
|
|
Service string
|
|
Region string
|
|
}
|
|
|
|
// Validate Signature Arguments
|
|
func (a *AWSOptions) Validate() error {
|
|
if a.Service == "" {
|
|
return errors.New("aws service cannot be empty")
|
|
}
|
|
if a.Region == "" {
|
|
return errors.New("aws region cannot be empty")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AWS v4 signer
|
|
type AWSSigner struct {
|
|
creds *aws.Credentials
|
|
signer *v4.Signer
|
|
options *AWSOptions
|
|
}
|
|
|
|
// SignHTTP
|
|
func (a *AWSSigner) SignHTTP(ctx context.Context, request *http.Request) error {
|
|
if region, ok := ctx.Value(SignerArg("region")).(string); ok && region != "" {
|
|
a.options.Region = region
|
|
}
|
|
if service, ok := ctx.Value(SignerArg("service")).(string); ok && service != "" {
|
|
a.options.Service = service
|
|
}
|
|
if err := a.options.Validate(); err != nil {
|
|
return err
|
|
}
|
|
// contentHash is sha256 hash of response body
|
|
contentHash := a.getPayloadHash(request)
|
|
if err := a.signer.SignHTTP(ctx, *a.creds, request, contentHash, a.options.Service, a.options.Region, time.Now()); err != nil {
|
|
return errkit.Wrap(err, "failed to sign http request using aws v4 signer")
|
|
}
|
|
// add x-amz-content-sha256 header to request
|
|
request.Header.Set("x-amz-content-sha256", contentHash)
|
|
return nil
|
|
}
|
|
|
|
// getPayloadHash returns hex encoded SHA-256 of request body
|
|
func (a *AWSSigner) getPayloadHash(request *http.Request) string {
|
|
if request.Body == nil {
|
|
// Default Hash of Empty Payload
|
|
return defaultEmptyPayloadHash
|
|
}
|
|
|
|
// no need to close request body since it is a reusablereadercloser
|
|
bin, err := io.ReadAll(request.Body)
|
|
if err != nil {
|
|
gologger.Error().Msgf("aws signer: failed to read request body: %s", err)
|
|
}
|
|
sha256Hash := sha256.Sum256(bin)
|
|
return hex.EncodeToString(sha256Hash[:])
|
|
}
|
|
|
|
// NewAwsSigner
|
|
func NewAwsSigner(opts *AWSOptions) (*AWSSigner, error) {
|
|
credcache := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(opts.AwsID, opts.AwsSecretToken, ""))
|
|
awscred, err := credcache.Retrieve(context.TODO())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &AWSSigner{
|
|
creds: &awscred,
|
|
options: opts,
|
|
signer: v4.NewSigner(),
|
|
}, nil
|
|
}
|
|
|
|
// NewAwsSignerFromConfig
|
|
func NewAwsSignerFromConfig(opts *AWSOptions) (*AWSSigner, error) {
|
|
/*
|
|
NewAwsSignerFromConfig fetches credentials from both
|
|
1. Environment Variables (old & new)
|
|
2. Shared Credentials ($HOME/.aws)
|
|
*/
|
|
cfg, err := awsconfig.LoadDefaultConfig(context.TODO())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
credcache := aws.NewCredentialsCache(cfg.Credentials)
|
|
awscred, err := credcache.Retrieve(context.TODO())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &AWSSigner{
|
|
creds: &awscred,
|
|
options: opts,
|
|
signer: v4.NewSigner(func(signer *v4.SignerOptions) {
|
|
// signer.DisableURIPathEscaping = true
|
|
}),
|
|
}, nil
|
|
}
|
|
|
|
var AwsSkipList = map[string]interface{}{
|
|
"region": struct{}{},
|
|
}
|
|
|
|
var AwsDefaultVars = map[string]interface{}{
|
|
"region": "us-east-2",
|
|
"service": "sts",
|
|
}
|
|
|
|
var AwsInternalOnlyVars = map[string]interface{}{
|
|
"aws-id": struct{}{},
|
|
"aws-secret": struct{}{},
|
|
}
|