text: /**
   * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
   * SPDX-License-Identifier: Apache-2.0.
   */
  
  #pragma once
  
  #include <aws/core/Core_EXPORTS.h>
  
  #include <aws/core/Region.h>
  #include <aws/core/utils/memory/AWSMemory.h>
  #include <aws/core/utils/memory/stl/AWSSet.h>
  #include <aws/core/utils/DateTime.h>
  #include <aws/core/utils/Array.h>
  #include <aws/core/utils/threading/ReaderWriterLock.h>
  #include <aws/core/utils/crypto/Sha256.h>
  #include <aws/core/utils/crypto/Sha256HMAC.h>
  
  #include <memory>
  #include <atomic>
  #include <chrono>
  
  namespace Aws
  {
      namespace Http
      {
          class HttpClientFactory;
          class HttpRequest;
      } // namespace Http
  
      namespace Utils
      {
          namespace Event
          {
              class Message;
          }
      } // namespace Utils
  
      namespace Auth
      {
          class AWSCredentials;
          class AWSCredentialsProvider;
          AWS_CORE_API extern const char SIGV4_SIGNER[];
          AWS_CORE_API extern const char EVENTSTREAM_SIGV4_SIGNER[];
          AWS_CORE_API extern const char SIGNATURE[];
          AWS_CORE_API extern const char NULL_SIGNER[];
      } // namespace Auth
  
      namespace Client
      {
          struct ClientConfiguration;
  
          /**
           * Auth Signer interface. Takes a generic AWS request and applies crypto tamper resistent signatures on the request.
           */
          class AWS_CORE_API AWSAuthSigner
          {
          public:
              AWSAuthSigner() : m_clockSkew() { m_clockSkew.store(std::chrono::milliseconds(0L)); }
              virtual ~AWSAuthSigner() = default;
  
              /**
               * Signs the request itself (usually by adding a signature header) based on info in the request and uri.
               */
              virtual bool SignRequest(Aws::Http::HttpRequest& request) const = 0;
  
              /**
               * Signs the request itself (usually by adding a signature header) based on info in the request and uri.
               * If signBody is false and https is being used then the body of the payload will not be signed.
               * The default virtual function, just calls SignRequest.
               */
              virtual bool SignRequest(Aws::Http::HttpRequest& request, bool signBody) const
              {
                  AWS_UNREFERENCED_PARAM(signBody);
                  return SignRequest(request);
              }
  
              /**
               * Signs the request itself (usually by adding a signature header) based on info in the request and uri.
               * If signBody is false and https is being used then the body of the payload will not be signed.
               * The default virtual function, just calls SignRequest.
               * Using m_region by default if parameter region is nullptr.
               */
              virtual bool SignRequest(Aws::Http::HttpRequest& request, const char* region, bool signBody) const
              {
                  AWS_UNREFERENCED_PARAM(signBody);
                  AWS_UNREFERENCED_PARAM(region);
                  return SignRequest(request);
              }
  
  
              /**
               * Signs a single event message in an event stream.
               * The input message buffer is copied and signed. The message's input buffer will be deallocated and a new
               * buffer will be assigned. The new buffer encodes the original message with its headers as the payload of
               * the new message. The signature of the original message will be added as a header to the new message.
               *
               * A Hex encoded signature of the previous event (or of the HTTP request headers in case of the first event)
               * is provided as the 'priorSignature' parameter. 'priorSignature' will contain the value of the new
               * signature after this call returns successfully.
               *
               * The function returns true if the message is successfully signed.
               */
              virtual bool SignEventMessage(Aws::Utils::Event::Message&, Aws::String& /* priorSignature */) const { return false; }
  
              /**
               * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request.
               * The URI can then be used in a normal HTTP call until expiration.
               */
              virtual bool PresignRequest(Aws::Http::HttpRequest& request, long long expirationInSeconds) const = 0;
  
              /**
              * Generates a signed Uri using the injected signer. for the supplied uri and http method and region. expirationInSeconds defaults
              * to 0 which is the default 7 days.
              * Using m_region by default if parameter region is nullptr.
              */
              virtual bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, long long expirationInSeconds = 0) const = 0;
  
              /**
              * Generates a signed Uri using the injected signer. for the supplied uri and http method, region, and service name. expirationInSeconds defaults
              * to 0 which is the default 7 days.
              * Using m_region by default if parameter region is nullptr.
              * Using m_serviceName by default if parameter serviceName is nullptr.
              */
              virtual bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, long long expirationInSeconds = 0) const = 0;
  
              /**
               * Return the signer's name
               */
              virtual const char* GetName() const = 0;
  
              /**
               * This handles detection of clock skew between clients and the server and adjusts the clock so that the next request will not
               * fail on the timestamp check.
               */
              virtual void SetClockSkew(const std::chrono::milliseconds& clockSkew) { m_clockSkew = clockSkew; }
  
              /**
               * Gets the timestamp being used by the signer. This may include a clock skew if a clock skew has been detected.
               */
              virtual Aws::Utils::DateTime GetSigningTimestamp() const { return Aws::Utils::DateTime::Now() + GetClockSkewOffset(); }
  
          protected:
              virtual std::chrono::milliseconds GetClockSkewOffset() const { return m_clockSkew.load(); }
  
              std::atomic<std::chrono::milliseconds> m_clockSkew;
          };
  
          /**
           * AWS Auth v4 Signer implementation of the AWSAuthSigner interface. More information on AWS Auth v4 Can be found here:
           * http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
           */
          class AWS_CORE_API AWSAuthV4Signer : public AWSAuthSigner
          {
  
          public:
              /**
               * Even though different payload signing polices, HTTP will force payload signing to be on.
               */
              enum class PayloadSigningPolicy
              {
                  /**
                   * Sign the request based on the value returned by AmazonWebServiceRequest::SignBody()
                   */
                  RequestDependent,
                  /**
                   * Always sign the body of the request.
                   */
                  Always,
                  /**
                   * Never sign the body of the request
                   */
                  Never
              };
              /**
               * credentialsProvider, source of AWS Credentials to sign requests with
               * serviceName,  canonical service name to sign with
               * region, region string to use in signature
               * signPayloads, if Always, the payload will have a sha256 computed on the body of the request. If this is set
               *    to Never, the sha256 will not be computed on the body. This is only useful for Amazon S3 over Https. If
               *    Https is not used then this flag will be ignored. If set to RequestDependent, compute or not is based on
               *    the value from AmazonWebServiceRequest::SignBody()
               */
              AWSAuthV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& credentialsProvider,
                              const char* serviceName, const Aws::String& region, PayloadSigningPolicy signingPolicy = PayloadSigningPolicy::RequestDependent,
                              bool urlEscapePath = true);
  
              virtual ~AWSAuthV4Signer();
  
              /**
               * AWSAuthV4signer's implementation of virtual function from base class
               * Return Auth Signer's name, here the value is specified in Aws::Auth::DEFAULT_AUTHV4_SIGNER.
               */
              const char* GetName() const override { return Aws::Auth::SIGV4_SIGNER; }
  
              /**
               * Signs the request itself based on info in the request and uri.
               * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm.
               */
              bool SignRequest(Aws::Http::HttpRequest& request) const override
              {
                  return SignRequest(request, m_region.c_str(), true/*signBody*/);
              }
  
              /**
              * Signs the request itself based on info in the request and uri.
              * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. If signBody is false
              * and https is being used then the body of the payload will not be signed.
              */
              bool SignRequest(Aws::Http::HttpRequest& request, bool signBody) const override
              {
                  return SignRequest(request, m_region.c_str(), signBody);
              }
  
              /**
               * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm. If signBody is false
               * and https is being used then the body of the payload will not be signed.
               * Using m_region by default if parameter region is nullptr.
               */
              bool SignRequest(Aws::Http::HttpRequest& request, const char* region, bool signBody) const override;
  
              /**
              * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request.
              * the region the signer was initialized with will be used for the signature.
              * The URI can then be used in a normal HTTP call until expiration.
              * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm.
              * expirationInSeconds defaults to 0 which provides a URI good for 7 days.
              */
              bool PresignRequest(Aws::Http::HttpRequest& request, long long expirationInSeconds = 0) const override;
  
              /**
              * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request.
              * The URI can then be used in a normal HTTP call until expiration.
              * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm.
              * expirationInSeconds defaults to 0 which provides a URI good for 7 days.
              * Using m_region by default if parameter region is nullptr.
              */
              bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, long long expirationInSeconds = 0) const override;
  
              /**
              * Takes a request and signs the URI based on the HttpMethod, URI and other info from the request.
              * The URI can then be used in a normal HTTP call until expiration.
              * Uses AWS Auth V4 signing method with SHA256 HMAC algorithm.
              * expirationInSeconds defaults to 0 which provides a URI good for 7 days.
              * Using m_region by default if parameter region is nullptr.
              * Using m_serviceName by default if parameter serviceName is nullptr.
              */
              bool PresignRequest(Aws::Http::HttpRequest& request, const char* region, const char* serviceName, long long expirationInSeconds = 0) const override;
  
              Aws::String GetServiceName() const { return m_serviceName; }
              Aws::String GetRegion() const { return m_region; }
              Aws::String GenerateSignature(const Aws::Auth::AWSCredentials& credentials,
                      const Aws::String& stringToSign, const Aws::String& simpleDate) const;
              bool ShouldSignHeader(const Aws::String& header) const;
  
          protected:
              bool m_includeSha256HashHeader;
  
          private:
  
              Aws::String GenerateSignature(const Aws::Auth::AWSCredentials& credentials,
                      const Aws::String& stringToSign, const Aws::String& simpleDate, const Aws::String& region,
                      const Aws::String& serviceName) const;
  
              Aws::String GenerateSignature(const Aws::String& stringToSign, const Aws::Utils::ByteBuffer& key) const;
              bool ServiceRequireUnsignedPayload(const Aws::String& serviceName) const;
              Aws::String ComputePayloadHash(Aws::Http::HttpRequest&) const;
              Aws::String GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate,
                      const Aws::String& canonicalRequestHash, const Aws::String& region,
                      const Aws::String& serviceName) const;
              Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey, const Aws::String& simpleDate) const;
              Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey,
                      const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const;
  
  
              std::shared_ptr<Auth::AWSCredentialsProvider> m_credentialsProvider;
              const Aws::String m_serviceName;
              const Aws::String m_region;
              Aws::UniquePtr<Aws::Utils::Crypto::Sha256> m_hash;
              Aws::UniquePtr<Aws::Utils::Crypto::Sha256HMAC> m_HMAC;
  
              Aws::Set<Aws::String> m_unsignedHeaders;
  
              //these next four fields are ONLY for caching purposes and do not change
              //the logical state of the signer. They are marked mutable so the
              //interface can remain const.
              mutable Aws::Utils::ByteBuffer m_partialSignature;
              mutable Aws::String m_currentDateStr;
              mutable Aws::String m_currentSecretKey;
              mutable Utils::Threading::ReaderWriterLock m_partialSignatureLock;
              PayloadSigningPolicy m_payloadSigningPolicy;
              bool m_urlEscapePath;
          };
  
          class AWS_CORE_API AWSAuthEventStreamV4Signer : public AWSAuthSigner
          {
          public:
              AWSAuthEventStreamV4Signer(const std::shared_ptr<Auth::AWSCredentialsProvider>& credentialsProvider,
                      const char* serviceName, const Aws::String& region);
  
              const char* GetName() const override { return Aws::Auth::EVENTSTREAM_SIGV4_SIGNER; }
  
              bool SignEventMessage(Aws::Utils::Event::Message&, Aws::String& priorSignature) const override;
  
              bool SignRequest(Aws::Http::HttpRequest& request) const override
              {
                  return SignRequest(request, m_region.c_str(), true);
              }
  
              bool SignRequest(Aws::Http::HttpRequest& request, bool signBody) const override
              {
                  return SignRequest(request, m_region.c_str(), signBody);
              }
  
              bool SignRequest(Aws::Http::HttpRequest& request, const char* region, bool signBody) const override;
  
              /**
               * Do nothing
               */
              bool PresignRequest(Aws::Http::HttpRequest&, long long) const override { return false; }
  
              /**
               * Do nothing
               */
              bool PresignRequest(Aws::Http::HttpRequest&, const char*, long long) const override { return false; }
  
              /**
               * Do nothing
               */
              bool PresignRequest(Aws::Http::HttpRequest&, const char*, const char*, long long) const override { return false; }
  
              bool ShouldSignHeader(const Aws::String& header) const;
          private:
              Utils::ByteBuffer GenerateSignature(const Aws::Auth::AWSCredentials& credentials,
                      const Aws::String& stringToSign, const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const;
              Utils::ByteBuffer GenerateSignature(const Aws::String& stringToSign, const Aws::Utils::ByteBuffer& key) const;
              Aws::String GenerateStringToSign(const Aws::String& dateValue, const Aws::String& simpleDate,
                      const Aws::String& canonicalRequestHash, const Aws::String& region,
                      const Aws::String& serviceName) const;
              Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey, const Aws::String& simpleDate) const;
              Aws::Utils::ByteBuffer ComputeHash(const Aws::String& secretKey,
                      const Aws::String& simpleDate, const Aws::String& region, const Aws::String& serviceName) const;
              const Aws::String m_serviceName;
              const Aws::String m_region;
              mutable Aws::Utils::Crypto::Sha256 m_hash;
              mutable Aws::Utils::Crypto::Sha256HMAC m_HMAC;
              mutable Utils::Threading::ReaderWriterLock m_derivedKeyLock;
              mutable Aws::Utils::ByteBuffer m_derivedKey;
              mutable Aws::String m_currentDateStr;
              mutable Aws::String m_currentSecretKey;
              Aws::Vector<Aws::String> m_unsignedHeaders;
              std::shared_ptr<Auth::AWSCredentialsProvider> m_credentialsProvider;
          };
  
  
          /**
           * A no-op implementation of the AWSAuthSigner interface
           */
          class AWS_CORE_API AWSNullSigner : public AWSAuthSigner
          {
          public:
              /**
               * AWSNullSigner's implementation of virtual function from base class
               * Here the returned value is specified in Aws::Auth::NULL_SIGNER.
               */
              const char* GetName() const override { return Aws::Auth::NULL_SIGNER; }
  
              /**
               * Do nothing
               */
              bool SignRequest(Aws::Http::HttpRequest&) const override { return true; }
  
              /**
               * Do nothing
               */
              bool SignEventMessage(Aws::Utils::Event::Message&, Aws::String& /* priorSignature */) const override { return true; }
  
              /**
               * Do nothing
               */
              bool PresignRequest(Aws::Http::HttpRequest&, long long) const override { return false; }
  
              /**
               * Do nothing
               */
              bool PresignRequest(Aws::Http::HttpRequest&, const char*, long long) const override { return false; }
  
              /**
               * Do nothing
               */
              bool PresignRequest(Aws::Http::HttpRequest&, const char*, const char*, long long) const override { return false; }
          };
  
      } // namespace Client
  } // namespace Aws
  
  