text: import { __awaiter, __generator, __values } from "tslib";
  import { toHex } from "@aws-sdk/util-hex-encoding";
  import { normalizeProvider } from "@aws-sdk/util-middleware";
  import { ALGORITHM_IDENTIFIER, ALGORITHM_QUERY_PARAM, AMZ_DATE_HEADER, AMZ_DATE_QUERY_PARAM, AUTH_HEADER, CREDENTIAL_QUERY_PARAM, EVENT_ALGORITHM_IDENTIFIER, EXPIRES_QUERY_PARAM, MAX_PRESIGNED_TTL, SHA256_HEADER, SIGNATURE_QUERY_PARAM, SIGNED_HEADERS_QUERY_PARAM, TOKEN_HEADER, TOKEN_QUERY_PARAM, } from "./constants";
  import { createScope, getSigningKey } from "./credentialDerivation";
  import { getCanonicalHeaders } from "./getCanonicalHeaders";
  import { getCanonicalQuery } from "./getCanonicalQuery";
  import { getPayloadHash } from "./getPayloadHash";
  import { hasHeader } from "./headerUtil";
  import { moveHeadersToQuery } from "./moveHeadersToQuery";
  import { prepareRequest } from "./prepareRequest";
  import { iso8601 } from "./utilDate";
  var SignatureV4 = (function () {
      function SignatureV4(_a) {
          var applyChecksum = _a.applyChecksum, credentials = _a.credentials, region = _a.region, service = _a.service, sha256 = _a.sha256, _b = _a.uriEscapePath, uriEscapePath = _b === void 0 ? true : _b;
          this.service = service;
          this.sha256 = sha256;
          this.uriEscapePath = uriEscapePath;
          this.applyChecksum = typeof applyChecksum === "boolean" ? applyChecksum : true;
          this.regionProvider = normalizeProvider(region);
          this.credentialProvider = normalizeProvider(credentials);
      }
      SignatureV4.prototype.presign = function (originalRequest, options) {
          if (options === void 0) { options = {}; }
          return __awaiter(this, void 0, void 0, function () {
              var _a, signingDate, _b, expiresIn, unsignableHeaders, unhoistableHeaders, signableHeaders, signingRegion, signingService, credentials, region, _c, _d, longDate, shortDate, scope, request, canonicalHeaders, _e, _f, _g, _h, _j, _k;
              return __generator(this, function (_l) {
                  switch (_l.label) {
                      case 0:
                          _a = options.signingDate, signingDate = _a === void 0 ? new Date() : _a, _b = options.expiresIn, expiresIn = _b === void 0 ? 3600 : _b, unsignableHeaders = options.unsignableHeaders, unhoistableHeaders = options.unhoistableHeaders, signableHeaders = options.signableHeaders, signingRegion = options.signingRegion, signingService = options.signingService;
                          return [4, this.credentialProvider()];
                      case 1:
                          credentials = _l.sent();
                          if (!(signingRegion !== null && signingRegion !== void 0)) return [3, 2];
                          _c = signingRegion;
                          return [3, 4];
                      case 2: return [4, this.regionProvider()];
                      case 3:
                          _c = (_l.sent());
                          _l.label = 4;
                      case 4:
                          region = _c;
                          _d = formatDate(signingDate), longDate = _d.longDate, shortDate = _d.shortDate;
                          if (expiresIn > MAX_PRESIGNED_TTL) {
                              return [2, Promise.reject("Signature version 4 presigned URLs" + " must have an expiration date less than one week in" + " the future")];
                          }
                          scope = createScope(shortDate, region, signingService !== null && signingService !== void 0 ? signingService : this.service);
                          request = moveHeadersToQuery(prepareRequest(originalRequest), { unhoistableHeaders: unhoistableHeaders });
                          if (credentials.sessionToken) {
                              request.query[TOKEN_QUERY_PARAM] = credentials.sessionToken;
                          }
                          request.query[ALGORITHM_QUERY_PARAM] = ALGORITHM_IDENTIFIER;
                          request.query[CREDENTIAL_QUERY_PARAM] = "".concat(credentials.accessKeyId, "/").concat(scope);
                          request.query[AMZ_DATE_QUERY_PARAM] = longDate;
                          request.query[EXPIRES_QUERY_PARAM] = expiresIn.toString(10);
                          canonicalHeaders = getCanonicalHeaders(request, unsignableHeaders, signableHeaders);
                          request.query[SIGNED_HEADERS_QUERY_PARAM] = getCanonicalHeaderList(canonicalHeaders);
                          _e = request.query;
                          _f = SIGNATURE_QUERY_PARAM;
                          _g = this.getSignature;
                          _h = [longDate,
                              scope,
                              this.getSigningKey(credentials, region, shortDate, signingService)];
                          _j = this.createCanonicalRequest;
                          _k = [request, canonicalHeaders];
                          return [4, getPayloadHash(originalRequest, this.sha256)];
                      case 5: return [4, _g.apply(this, _h.concat([_j.apply(this, _k.concat([_l.sent()]))]))];
                      case 6:
                          _e[_f] = _l.sent();
                          return [2, request];
                  }
              });
          });
      };
      SignatureV4.prototype.sign = function (toSign, options) {
          return __awaiter(this, void 0, void 0, function () {
              return __generator(this, function (_a) {
                  if (typeof toSign === "string") {
                      return [2, this.signString(toSign, options)];
                  }
                  else if (toSign.headers && toSign.payload) {
                      return [2, this.signEvent(toSign, options)];
                  }
                  else {
                      return [2, this.signRequest(toSign, options)];
                  }
                  return [2];
              });
          });
      };
      SignatureV4.prototype.signEvent = function (_a, _b) {
          var headers = _a.headers, payload = _a.payload;
          var _c = _b.signingDate, signingDate = _c === void 0 ? new Date() : _c, priorSignature = _b.priorSignature, signingRegion = _b.signingRegion, signingService = _b.signingService;
          return __awaiter(this, void 0, void 0, function () {
              var region, _d, _e, shortDate, longDate, scope, hashedPayload, hash, hashedHeaders, _f, stringToSign;
              return __generator(this, function (_g) {
                  switch (_g.label) {
                      case 0:
                          if (!(signingRegion !== null && signingRegion !== void 0)) return [3, 1];
                          _d = signingRegion;
                          return [3, 3];
                      case 1: return [4, this.regionProvider()];
                      case 2:
                          _d = (_g.sent());
                          _g.label = 3;
                      case 3:
                          region = _d;
                          _e = formatDate(signingDate), shortDate = _e.shortDate, longDate = _e.longDate;
                          scope = createScope(shortDate, region, signingService !== null && signingService !== void 0 ? signingService : this.service);
                          return [4, getPayloadHash({ headers: {}, body: payload }, this.sha256)];
                      case 4:
                          hashedPayload = _g.sent();
                          hash = new this.sha256();
                          hash.update(headers);
                          _f = toHex;
                          return [4, hash.digest()];
                      case 5:
                          hashedHeaders = _f.apply(void 0, [_g.sent()]);
                          stringToSign = [
                              EVENT_ALGORITHM_IDENTIFIER,
                              longDate,
                              scope,
                              priorSignature,
                              hashedHeaders,
                              hashedPayload,
                          ].join("\n");
                          return [2, this.signString(stringToSign, { signingDate: signingDate, signingRegion: region, signingService: signingService })];
                  }
              });
          });
      };
      SignatureV4.prototype.signString = function (stringToSign, _a) {
          var _b = _a === void 0 ? {} : _a, _c = _b.signingDate, signingDate = _c === void 0 ? new Date() : _c, signingRegion = _b.signingRegion, signingService = _b.signingService;
          return __awaiter(this, void 0, void 0, function () {
              var credentials, region, _d, shortDate, hash, _e, _f, _g;
              return __generator(this, function (_h) {
                  switch (_h.label) {
                      case 0: return [4, this.credentialProvider()];
                      case 1:
                          credentials = _h.sent();
                          if (!(signingRegion !== null && signingRegion !== void 0)) return [3, 2];
                          _d = signingRegion;
                          return [3, 4];
                      case 2: return [4, this.regionProvider()];
                      case 3:
                          _d = (_h.sent());
                          _h.label = 4;
                      case 4:
                          region = _d;
                          shortDate = formatDate(signingDate).shortDate;
                          _f = (_e = this.sha256).bind;
                          return [4, this.getSigningKey(credentials, region, shortDate, signingService)];
                      case 5:
                          hash = new (_f.apply(_e, [void 0, _h.sent()]))();
                          hash.update(stringToSign);
                          _g = toHex;
                          return [4, hash.digest()];
                      case 6: return [2, _g.apply(void 0, [_h.sent()])];
                  }
              });
          });
      };
      SignatureV4.prototype.signRequest = function (requestToSign, _a) {
          var _b = _a === void 0 ? {} : _a, _c = _b.signingDate, signingDate = _c === void 0 ? new Date() : _c, signableHeaders = _b.signableHeaders, unsignableHeaders = _b.unsignableHeaders, signingRegion = _b.signingRegion, signingService = _b.signingService;
          return __awaiter(this, void 0, void 0, function () {
              var credentials, region, _d, request, _e, longDate, shortDate, scope, payloadHash, canonicalHeaders, signature;
              return __generator(this, function (_f) {
                  switch (_f.label) {
                      case 0: return [4, this.credentialProvider()];
                      case 1:
                          credentials = _f.sent();
                          if (!(signingRegion !== null && signingRegion !== void 0)) return [3, 2];
                          _d = signingRegion;
                          return [3, 4];
                      case 2: return [4, this.regionProvider()];
                      case 3:
                          _d = (_f.sent());
                          _f.label = 4;
                      case 4:
                          region = _d;
                          request = prepareRequest(requestToSign);
                          _e = formatDate(signingDate), longDate = _e.longDate, shortDate = _e.shortDate;
                          scope = createScope(shortDate, region, signingService !== null && signingService !== void 0 ? signingService : this.service);
                          request.headers[AMZ_DATE_HEADER] = longDate;
                          if (credentials.sessionToken) {
                              request.headers[TOKEN_HEADER] = credentials.sessionToken;
                          }
                          return [4, getPayloadHash(request, this.sha256)];
                      case 5:
                          payloadHash = _f.sent();
                          if (!hasHeader(SHA256_HEADER, request.headers) && this.applyChecksum) {
                              request.headers[SHA256_HEADER] = payloadHash;
                          }
                          canonicalHeaders = getCanonicalHeaders(request, unsignableHeaders, signableHeaders);
                          return [4, this.getSignature(longDate, scope, this.getSigningKey(credentials, region, shortDate, signingService), this.createCanonicalRequest(request, canonicalHeaders, payloadHash))];
                      case 6:
                          signature = _f.sent();
                          request.headers[AUTH_HEADER] =
                              "".concat(ALGORITHM_IDENTIFIER, " ") +
                                  "Credential=".concat(credentials.accessKeyId, "/").concat(scope, ", ") +
                                  "SignedHeaders=".concat(getCanonicalHeaderList(canonicalHeaders), ", ") +
                                  "Signature=".concat(signature);
                          return [2, request];
                  }
              });
          });
      };
      SignatureV4.prototype.createCanonicalRequest = function (request, canonicalHeaders, payloadHash) {
          var sortedHeaders = Object.keys(canonicalHeaders).sort();
          return "".concat(request.method, "\n").concat(this.getCanonicalPath(request), "\n").concat(getCanonicalQuery(request), "\n").concat(sortedHeaders.map(function (name) { return "".concat(name, ":").concat(canonicalHeaders[name]); }).join("\n"), "\n\n").concat(sortedHeaders.join(";"), "\n").concat(payloadHash);
      };
      SignatureV4.prototype.createStringToSign = function (longDate, credentialScope, canonicalRequest) {
          return __awaiter(this, void 0, void 0, function () {
              var hash, hashedRequest;
              return __generator(this, function (_a) {
                  switch (_a.label) {
                      case 0:
                          hash = new this.sha256();
                          hash.update(canonicalRequest);
                          return [4, hash.digest()];
                      case 1:
                          hashedRequest = _a.sent();
                          return [2, "".concat(ALGORITHM_IDENTIFIER, "\n").concat(longDate, "\n").concat(credentialScope, "\n").concat(toHex(hashedRequest))];
                  }
              });
          });
      };
      SignatureV4.prototype.getCanonicalPath = function (_a) {
          var e_1, _b;
          var path = _a.path;
          if (this.uriEscapePath) {
              var normalizedPathSegments = [];
              try {
                  for (var _c = __values(path.split("/")), _d = _c.next(); !_d.done; _d = _c.next()) {
                      var pathSegment = _d.value;
                      if ((pathSegment === null || pathSegment === void 0 ? void 0 : pathSegment.length) === 0)
                          continue;
                      if (pathSegment === ".")
                          continue;
                      if (pathSegment === "..") {
                          normalizedPathSegments.pop();
                      }
                      else {
                          normalizedPathSegments.push(pathSegment);
                      }
                  }
              }
              catch (e_1_1) { e_1 = { error: e_1_1 }; }
              finally {
                  try {
                      if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
                  }
                  finally { if (e_1) throw e_1.error; }
              }
              var normalizedPath = "".concat((path === null || path === void 0 ? void 0 : path.startsWith("/")) ? "/" : "").concat(normalizedPathSegments.join("/")).concat(normalizedPathSegments.length > 0 && (path === null || path === void 0 ? void 0 : path.endsWith("/")) ? "/" : "");
              var doubleEncoded = encodeURIComponent(normalizedPath);
              return doubleEncoded.replace(/%2F/g, "/");
          }
          return path;
      };
      SignatureV4.prototype.getSignature = function (longDate, credentialScope, keyPromise, canonicalRequest) {
          return __awaiter(this, void 0, void 0, function () {
              var stringToSign, hash, _a, _b, _c;
              return __generator(this, function (_d) {
                  switch (_d.label) {
                      case 0: return [4, this.createStringToSign(longDate, credentialScope, canonicalRequest)];
                      case 1:
                          stringToSign = _d.sent();
                          _b = (_a = this.sha256).bind;
                          return [4, keyPromise];
                      case 2:
                          hash = new (_b.apply(_a, [void 0, _d.sent()]))();
                          hash.update(stringToSign);
                          _c = toHex;
                          return [4, hash.digest()];
                      case 3: return [2, _c.apply(void 0, [_d.sent()])];
                  }
              });
          });
      };
      SignatureV4.prototype.getSigningKey = function (credentials, region, shortDate, service) {
          return getSigningKey(this.sha256, credentials, shortDate, region, service || this.service);
      };
      return SignatureV4;
  }());
  export { SignatureV4 };
  var formatDate = function (now) {
      var longDate = iso8601(now).replace(/[\-:]/g, "");
      return {
          longDate: longDate,
          shortDate: longDate.slice(0, 8),
      };
  };
  var getCanonicalHeaderList = function (headers) { return Object.keys(headers).sort().join(";"); };
  