590 lines
22 KiB
JavaScript
590 lines
22 KiB
JavaScript
|
var __defProp = Object.defineProperty;
|
||
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
||
|
var __export = (target, all) => {
|
||
|
for (var name in all)
|
||
|
__defProp(target, name, { get: all[name], enumerable: true });
|
||
|
};
|
||
|
var __copyProps = (to, from, except, desc) => {
|
||
|
if (from && typeof from === "object" || typeof from === "function") {
|
||
|
for (let key of __getOwnPropNames(from))
|
||
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
||
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||
|
}
|
||
|
return to;
|
||
|
};
|
||
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||
|
|
||
|
// src/index.ts
|
||
|
var src_exports = {};
|
||
|
__export(src_exports, {
|
||
|
SignatureV4: () => SignatureV4,
|
||
|
clearCredentialCache: () => clearCredentialCache,
|
||
|
createScope: () => createScope,
|
||
|
getCanonicalHeaders: () => getCanonicalHeaders,
|
||
|
getCanonicalQuery: () => getCanonicalQuery,
|
||
|
getPayloadHash: () => getPayloadHash,
|
||
|
getSigningKey: () => getSigningKey,
|
||
|
moveHeadersToQuery: () => moveHeadersToQuery,
|
||
|
prepareRequest: () => prepareRequest
|
||
|
});
|
||
|
module.exports = __toCommonJS(src_exports);
|
||
|
|
||
|
// src/SignatureV4.ts
|
||
|
|
||
|
var import_util_middleware = require("@smithy/util-middleware");
|
||
|
|
||
|
var import_util_utf84 = require("@smithy/util-utf8");
|
||
|
|
||
|
// src/constants.ts
|
||
|
var ALGORITHM_QUERY_PARAM = "X-Amz-Algorithm";
|
||
|
var CREDENTIAL_QUERY_PARAM = "X-Amz-Credential";
|
||
|
var AMZ_DATE_QUERY_PARAM = "X-Amz-Date";
|
||
|
var SIGNED_HEADERS_QUERY_PARAM = "X-Amz-SignedHeaders";
|
||
|
var EXPIRES_QUERY_PARAM = "X-Amz-Expires";
|
||
|
var SIGNATURE_QUERY_PARAM = "X-Amz-Signature";
|
||
|
var TOKEN_QUERY_PARAM = "X-Amz-Security-Token";
|
||
|
var AUTH_HEADER = "authorization";
|
||
|
var AMZ_DATE_HEADER = AMZ_DATE_QUERY_PARAM.toLowerCase();
|
||
|
var DATE_HEADER = "date";
|
||
|
var GENERATED_HEADERS = [AUTH_HEADER, AMZ_DATE_HEADER, DATE_HEADER];
|
||
|
var SIGNATURE_HEADER = SIGNATURE_QUERY_PARAM.toLowerCase();
|
||
|
var SHA256_HEADER = "x-amz-content-sha256";
|
||
|
var TOKEN_HEADER = TOKEN_QUERY_PARAM.toLowerCase();
|
||
|
var ALWAYS_UNSIGNABLE_HEADERS = {
|
||
|
authorization: true,
|
||
|
"cache-control": true,
|
||
|
connection: true,
|
||
|
expect: true,
|
||
|
from: true,
|
||
|
"keep-alive": true,
|
||
|
"max-forwards": true,
|
||
|
pragma: true,
|
||
|
referer: true,
|
||
|
te: true,
|
||
|
trailer: true,
|
||
|
"transfer-encoding": true,
|
||
|
upgrade: true,
|
||
|
"user-agent": true,
|
||
|
"x-amzn-trace-id": true
|
||
|
};
|
||
|
var PROXY_HEADER_PATTERN = /^proxy-/;
|
||
|
var SEC_HEADER_PATTERN = /^sec-/;
|
||
|
var ALGORITHM_IDENTIFIER = "AWS4-HMAC-SHA256";
|
||
|
var EVENT_ALGORITHM_IDENTIFIER = "AWS4-HMAC-SHA256-PAYLOAD";
|
||
|
var UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD";
|
||
|
var MAX_CACHE_SIZE = 50;
|
||
|
var KEY_TYPE_IDENTIFIER = "aws4_request";
|
||
|
var MAX_PRESIGNED_TTL = 60 * 60 * 24 * 7;
|
||
|
|
||
|
// src/credentialDerivation.ts
|
||
|
var import_util_hex_encoding = require("@smithy/util-hex-encoding");
|
||
|
var import_util_utf8 = require("@smithy/util-utf8");
|
||
|
var signingKeyCache = {};
|
||
|
var cacheQueue = [];
|
||
|
var createScope = /* @__PURE__ */ __name((shortDate, region, service) => `${shortDate}/${region}/${service}/${KEY_TYPE_IDENTIFIER}`, "createScope");
|
||
|
var getSigningKey = /* @__PURE__ */ __name(async (sha256Constructor, credentials, shortDate, region, service) => {
|
||
|
const credsHash = await hmac(sha256Constructor, credentials.secretAccessKey, credentials.accessKeyId);
|
||
|
const cacheKey = `${shortDate}:${region}:${service}:${(0, import_util_hex_encoding.toHex)(credsHash)}:${credentials.sessionToken}`;
|
||
|
if (cacheKey in signingKeyCache) {
|
||
|
return signingKeyCache[cacheKey];
|
||
|
}
|
||
|
cacheQueue.push(cacheKey);
|
||
|
while (cacheQueue.length > MAX_CACHE_SIZE) {
|
||
|
delete signingKeyCache[cacheQueue.shift()];
|
||
|
}
|
||
|
let key = `AWS4${credentials.secretAccessKey}`;
|
||
|
for (const signable of [shortDate, region, service, KEY_TYPE_IDENTIFIER]) {
|
||
|
key = await hmac(sha256Constructor, key, signable);
|
||
|
}
|
||
|
return signingKeyCache[cacheKey] = key;
|
||
|
}, "getSigningKey");
|
||
|
var clearCredentialCache = /* @__PURE__ */ __name(() => {
|
||
|
cacheQueue.length = 0;
|
||
|
Object.keys(signingKeyCache).forEach((cacheKey) => {
|
||
|
delete signingKeyCache[cacheKey];
|
||
|
});
|
||
|
}, "clearCredentialCache");
|
||
|
var hmac = /* @__PURE__ */ __name((ctor, secret, data) => {
|
||
|
const hash = new ctor(secret);
|
||
|
hash.update((0, import_util_utf8.toUint8Array)(data));
|
||
|
return hash.digest();
|
||
|
}, "hmac");
|
||
|
|
||
|
// src/getCanonicalHeaders.ts
|
||
|
var getCanonicalHeaders = /* @__PURE__ */ __name(({ headers }, unsignableHeaders, signableHeaders) => {
|
||
|
const canonical = {};
|
||
|
for (const headerName of Object.keys(headers).sort()) {
|
||
|
if (headers[headerName] == void 0) {
|
||
|
continue;
|
||
|
}
|
||
|
const canonicalHeaderName = headerName.toLowerCase();
|
||
|
if (canonicalHeaderName in ALWAYS_UNSIGNABLE_HEADERS || (unsignableHeaders == null ? void 0 : unsignableHeaders.has(canonicalHeaderName)) || PROXY_HEADER_PATTERN.test(canonicalHeaderName) || SEC_HEADER_PATTERN.test(canonicalHeaderName)) {
|
||
|
if (!signableHeaders || signableHeaders && !signableHeaders.has(canonicalHeaderName)) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
canonical[canonicalHeaderName] = headers[headerName].trim().replace(/\s+/g, " ");
|
||
|
}
|
||
|
return canonical;
|
||
|
}, "getCanonicalHeaders");
|
||
|
|
||
|
// src/getCanonicalQuery.ts
|
||
|
var import_util_uri_escape = require("@smithy/util-uri-escape");
|
||
|
var getCanonicalQuery = /* @__PURE__ */ __name(({ query = {} }) => {
|
||
|
const keys = [];
|
||
|
const serialized = {};
|
||
|
for (const key of Object.keys(query).sort()) {
|
||
|
if (key.toLowerCase() === SIGNATURE_HEADER) {
|
||
|
continue;
|
||
|
}
|
||
|
keys.push(key);
|
||
|
const value = query[key];
|
||
|
if (typeof value === "string") {
|
||
|
serialized[key] = `${(0, import_util_uri_escape.escapeUri)(key)}=${(0, import_util_uri_escape.escapeUri)(value)}`;
|
||
|
} else if (Array.isArray(value)) {
|
||
|
serialized[key] = value.slice(0).reduce(
|
||
|
(encoded, value2) => encoded.concat([`${(0, import_util_uri_escape.escapeUri)(key)}=${(0, import_util_uri_escape.escapeUri)(value2)}`]),
|
||
|
[]
|
||
|
).sort().join("&");
|
||
|
}
|
||
|
}
|
||
|
return keys.map((key) => serialized[key]).filter((serialized2) => serialized2).join("&");
|
||
|
}, "getCanonicalQuery");
|
||
|
|
||
|
// src/getPayloadHash.ts
|
||
|
var import_is_array_buffer = require("@smithy/is-array-buffer");
|
||
|
|
||
|
var import_util_utf82 = require("@smithy/util-utf8");
|
||
|
var getPayloadHash = /* @__PURE__ */ __name(async ({ headers, body }, hashConstructor) => {
|
||
|
for (const headerName of Object.keys(headers)) {
|
||
|
if (headerName.toLowerCase() === SHA256_HEADER) {
|
||
|
return headers[headerName];
|
||
|
}
|
||
|
}
|
||
|
if (body == void 0) {
|
||
|
return "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
||
|
} else if (typeof body === "string" || ArrayBuffer.isView(body) || (0, import_is_array_buffer.isArrayBuffer)(body)) {
|
||
|
const hashCtor = new hashConstructor();
|
||
|
hashCtor.update((0, import_util_utf82.toUint8Array)(body));
|
||
|
return (0, import_util_hex_encoding.toHex)(await hashCtor.digest());
|
||
|
}
|
||
|
return UNSIGNED_PAYLOAD;
|
||
|
}, "getPayloadHash");
|
||
|
|
||
|
// src/HeaderFormatter.ts
|
||
|
|
||
|
var import_util_utf83 = require("@smithy/util-utf8");
|
||
|
var _HeaderFormatter = class _HeaderFormatter {
|
||
|
format(headers) {
|
||
|
const chunks = [];
|
||
|
for (const headerName of Object.keys(headers)) {
|
||
|
const bytes = (0, import_util_utf83.fromUtf8)(headerName);
|
||
|
chunks.push(Uint8Array.from([bytes.byteLength]), bytes, this.formatHeaderValue(headers[headerName]));
|
||
|
}
|
||
|
const out = new Uint8Array(chunks.reduce((carry, bytes) => carry + bytes.byteLength, 0));
|
||
|
let position = 0;
|
||
|
for (const chunk of chunks) {
|
||
|
out.set(chunk, position);
|
||
|
position += chunk.byteLength;
|
||
|
}
|
||
|
return out;
|
||
|
}
|
||
|
formatHeaderValue(header) {
|
||
|
switch (header.type) {
|
||
|
case "boolean":
|
||
|
return Uint8Array.from([header.value ? 0 /* boolTrue */ : 1 /* boolFalse */]);
|
||
|
case "byte":
|
||
|
return Uint8Array.from([2 /* byte */, header.value]);
|
||
|
case "short":
|
||
|
const shortView = new DataView(new ArrayBuffer(3));
|
||
|
shortView.setUint8(0, 3 /* short */);
|
||
|
shortView.setInt16(1, header.value, false);
|
||
|
return new Uint8Array(shortView.buffer);
|
||
|
case "integer":
|
||
|
const intView = new DataView(new ArrayBuffer(5));
|
||
|
intView.setUint8(0, 4 /* integer */);
|
||
|
intView.setInt32(1, header.value, false);
|
||
|
return new Uint8Array(intView.buffer);
|
||
|
case "long":
|
||
|
const longBytes = new Uint8Array(9);
|
||
|
longBytes[0] = 5 /* long */;
|
||
|
longBytes.set(header.value.bytes, 1);
|
||
|
return longBytes;
|
||
|
case "binary":
|
||
|
const binView = new DataView(new ArrayBuffer(3 + header.value.byteLength));
|
||
|
binView.setUint8(0, 6 /* byteArray */);
|
||
|
binView.setUint16(1, header.value.byteLength, false);
|
||
|
const binBytes = new Uint8Array(binView.buffer);
|
||
|
binBytes.set(header.value, 3);
|
||
|
return binBytes;
|
||
|
case "string":
|
||
|
const utf8Bytes = (0, import_util_utf83.fromUtf8)(header.value);
|
||
|
const strView = new DataView(new ArrayBuffer(3 + utf8Bytes.byteLength));
|
||
|
strView.setUint8(0, 7 /* string */);
|
||
|
strView.setUint16(1, utf8Bytes.byteLength, false);
|
||
|
const strBytes = new Uint8Array(strView.buffer);
|
||
|
strBytes.set(utf8Bytes, 3);
|
||
|
return strBytes;
|
||
|
case "timestamp":
|
||
|
const tsBytes = new Uint8Array(9);
|
||
|
tsBytes[0] = 8 /* timestamp */;
|
||
|
tsBytes.set(Int64.fromNumber(header.value.valueOf()).bytes, 1);
|
||
|
return tsBytes;
|
||
|
case "uuid":
|
||
|
if (!UUID_PATTERN.test(header.value)) {
|
||
|
throw new Error(`Invalid UUID received: ${header.value}`);
|
||
|
}
|
||
|
const uuidBytes = new Uint8Array(17);
|
||
|
uuidBytes[0] = 9 /* uuid */;
|
||
|
uuidBytes.set((0, import_util_hex_encoding.fromHex)(header.value.replace(/\-/g, "")), 1);
|
||
|
return uuidBytes;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
__name(_HeaderFormatter, "HeaderFormatter");
|
||
|
var HeaderFormatter = _HeaderFormatter;
|
||
|
var UUID_PATTERN = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
|
||
|
var _Int64 = class _Int64 {
|
||
|
constructor(bytes) {
|
||
|
this.bytes = bytes;
|
||
|
if (bytes.byteLength !== 8) {
|
||
|
throw new Error("Int64 buffers must be exactly 8 bytes");
|
||
|
}
|
||
|
}
|
||
|
static fromNumber(number) {
|
||
|
if (number > 9223372036854776e3 || number < -9223372036854776e3) {
|
||
|
throw new Error(`${number} is too large (or, if negative, too small) to represent as an Int64`);
|
||
|
}
|
||
|
const bytes = new Uint8Array(8);
|
||
|
for (let i = 7, remaining = Math.abs(Math.round(number)); i > -1 && remaining > 0; i--, remaining /= 256) {
|
||
|
bytes[i] = remaining;
|
||
|
}
|
||
|
if (number < 0) {
|
||
|
negate(bytes);
|
||
|
}
|
||
|
return new _Int64(bytes);
|
||
|
}
|
||
|
/**
|
||
|
* Called implicitly by infix arithmetic operators.
|
||
|
*/
|
||
|
valueOf() {
|
||
|
const bytes = this.bytes.slice(0);
|
||
|
const negative = bytes[0] & 128;
|
||
|
if (negative) {
|
||
|
negate(bytes);
|
||
|
}
|
||
|
return parseInt((0, import_util_hex_encoding.toHex)(bytes), 16) * (negative ? -1 : 1);
|
||
|
}
|
||
|
toString() {
|
||
|
return String(this.valueOf());
|
||
|
}
|
||
|
};
|
||
|
__name(_Int64, "Int64");
|
||
|
var Int64 = _Int64;
|
||
|
function negate(bytes) {
|
||
|
for (let i = 0; i < 8; i++) {
|
||
|
bytes[i] ^= 255;
|
||
|
}
|
||
|
for (let i = 7; i > -1; i--) {
|
||
|
bytes[i]++;
|
||
|
if (bytes[i] !== 0)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
__name(negate, "negate");
|
||
|
|
||
|
// src/headerUtil.ts
|
||
|
var hasHeader = /* @__PURE__ */ __name((soughtHeader, headers) => {
|
||
|
soughtHeader = soughtHeader.toLowerCase();
|
||
|
for (const headerName of Object.keys(headers)) {
|
||
|
if (soughtHeader === headerName.toLowerCase()) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}, "hasHeader");
|
||
|
|
||
|
// src/cloneRequest.ts
|
||
|
var cloneRequest = /* @__PURE__ */ __name(({ headers, query, ...rest }) => ({
|
||
|
...rest,
|
||
|
headers: { ...headers },
|
||
|
query: query ? cloneQuery(query) : void 0
|
||
|
}), "cloneRequest");
|
||
|
var cloneQuery = /* @__PURE__ */ __name((query) => Object.keys(query).reduce((carry, paramName) => {
|
||
|
const param = query[paramName];
|
||
|
return {
|
||
|
...carry,
|
||
|
[paramName]: Array.isArray(param) ? [...param] : param
|
||
|
};
|
||
|
}, {}), "cloneQuery");
|
||
|
|
||
|
// src/moveHeadersToQuery.ts
|
||
|
var moveHeadersToQuery = /* @__PURE__ */ __name((request, options = {}) => {
|
||
|
var _a;
|
||
|
const { headers, query = {} } = typeof request.clone === "function" ? request.clone() : cloneRequest(request);
|
||
|
for (const name of Object.keys(headers)) {
|
||
|
const lname = name.toLowerCase();
|
||
|
if (lname.slice(0, 6) === "x-amz-" && !((_a = options.unhoistableHeaders) == null ? void 0 : _a.has(lname))) {
|
||
|
query[name] = headers[name];
|
||
|
delete headers[name];
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
...request,
|
||
|
headers,
|
||
|
query
|
||
|
};
|
||
|
}, "moveHeadersToQuery");
|
||
|
|
||
|
// src/prepareRequest.ts
|
||
|
var prepareRequest = /* @__PURE__ */ __name((request) => {
|
||
|
request = typeof request.clone === "function" ? request.clone() : cloneRequest(request);
|
||
|
for (const headerName of Object.keys(request.headers)) {
|
||
|
if (GENERATED_HEADERS.indexOf(headerName.toLowerCase()) > -1) {
|
||
|
delete request.headers[headerName];
|
||
|
}
|
||
|
}
|
||
|
return request;
|
||
|
}, "prepareRequest");
|
||
|
|
||
|
// src/utilDate.ts
|
||
|
var iso8601 = /* @__PURE__ */ __name((time) => toDate(time).toISOString().replace(/\.\d{3}Z$/, "Z"), "iso8601");
|
||
|
var toDate = /* @__PURE__ */ __name((time) => {
|
||
|
if (typeof time === "number") {
|
||
|
return new Date(time * 1e3);
|
||
|
}
|
||
|
if (typeof time === "string") {
|
||
|
if (Number(time)) {
|
||
|
return new Date(Number(time) * 1e3);
|
||
|
}
|
||
|
return new Date(time);
|
||
|
}
|
||
|
return time;
|
||
|
}, "toDate");
|
||
|
|
||
|
// src/SignatureV4.ts
|
||
|
var _SignatureV4 = class _SignatureV4 {
|
||
|
constructor({
|
||
|
applyChecksum,
|
||
|
credentials,
|
||
|
region,
|
||
|
service,
|
||
|
sha256,
|
||
|
uriEscapePath = true
|
||
|
}) {
|
||
|
this.headerFormatter = new HeaderFormatter();
|
||
|
this.service = service;
|
||
|
this.sha256 = sha256;
|
||
|
this.uriEscapePath = uriEscapePath;
|
||
|
this.applyChecksum = typeof applyChecksum === "boolean" ? applyChecksum : true;
|
||
|
this.regionProvider = (0, import_util_middleware.normalizeProvider)(region);
|
||
|
this.credentialProvider = (0, import_util_middleware.normalizeProvider)(credentials);
|
||
|
}
|
||
|
async presign(originalRequest, options = {}) {
|
||
|
const {
|
||
|
signingDate = /* @__PURE__ */ new Date(),
|
||
|
expiresIn = 3600,
|
||
|
unsignableHeaders,
|
||
|
unhoistableHeaders,
|
||
|
signableHeaders,
|
||
|
signingRegion,
|
||
|
signingService
|
||
|
} = options;
|
||
|
const credentials = await this.credentialProvider();
|
||
|
this.validateResolvedCredentials(credentials);
|
||
|
const region = signingRegion ?? await this.regionProvider();
|
||
|
const { longDate, shortDate } = formatDate(signingDate);
|
||
|
if (expiresIn > MAX_PRESIGNED_TTL) {
|
||
|
return Promise.reject(
|
||
|
"Signature version 4 presigned URLs must have an expiration date less than one week in the future"
|
||
|
);
|
||
|
}
|
||
|
const scope = createScope(shortDate, region, signingService ?? this.service);
|
||
|
const request = moveHeadersToQuery(prepareRequest(originalRequest), { unhoistableHeaders });
|
||
|
if (credentials.sessionToken) {
|
||
|
request.query[TOKEN_QUERY_PARAM] = credentials.sessionToken;
|
||
|
}
|
||
|
request.query[ALGORITHM_QUERY_PARAM] = ALGORITHM_IDENTIFIER;
|
||
|
request.query[CREDENTIAL_QUERY_PARAM] = `${credentials.accessKeyId}/${scope}`;
|
||
|
request.query[AMZ_DATE_QUERY_PARAM] = longDate;
|
||
|
request.query[EXPIRES_QUERY_PARAM] = expiresIn.toString(10);
|
||
|
const canonicalHeaders = getCanonicalHeaders(request, unsignableHeaders, signableHeaders);
|
||
|
request.query[SIGNED_HEADERS_QUERY_PARAM] = getCanonicalHeaderList(canonicalHeaders);
|
||
|
request.query[SIGNATURE_QUERY_PARAM] = await this.getSignature(
|
||
|
longDate,
|
||
|
scope,
|
||
|
this.getSigningKey(credentials, region, shortDate, signingService),
|
||
|
this.createCanonicalRequest(request, canonicalHeaders, await getPayloadHash(originalRequest, this.sha256))
|
||
|
);
|
||
|
return request;
|
||
|
}
|
||
|
async sign(toSign, options) {
|
||
|
if (typeof toSign === "string") {
|
||
|
return this.signString(toSign, options);
|
||
|
} else if (toSign.headers && toSign.payload) {
|
||
|
return this.signEvent(toSign, options);
|
||
|
} else if (toSign.message) {
|
||
|
return this.signMessage(toSign, options);
|
||
|
} else {
|
||
|
return this.signRequest(toSign, options);
|
||
|
}
|
||
|
}
|
||
|
async signEvent({ headers, payload }, { signingDate = /* @__PURE__ */ new Date(), priorSignature, signingRegion, signingService }) {
|
||
|
const region = signingRegion ?? await this.regionProvider();
|
||
|
const { shortDate, longDate } = formatDate(signingDate);
|
||
|
const scope = createScope(shortDate, region, signingService ?? this.service);
|
||
|
const hashedPayload = await getPayloadHash({ headers: {}, body: payload }, this.sha256);
|
||
|
const hash = new this.sha256();
|
||
|
hash.update(headers);
|
||
|
const hashedHeaders = (0, import_util_hex_encoding.toHex)(await hash.digest());
|
||
|
const stringToSign = [
|
||
|
EVENT_ALGORITHM_IDENTIFIER,
|
||
|
longDate,
|
||
|
scope,
|
||
|
priorSignature,
|
||
|
hashedHeaders,
|
||
|
hashedPayload
|
||
|
].join("\n");
|
||
|
return this.signString(stringToSign, { signingDate, signingRegion: region, signingService });
|
||
|
}
|
||
|
async signMessage(signableMessage, { signingDate = /* @__PURE__ */ new Date(), signingRegion, signingService }) {
|
||
|
const promise = this.signEvent(
|
||
|
{
|
||
|
headers: this.headerFormatter.format(signableMessage.message.headers),
|
||
|
payload: signableMessage.message.body
|
||
|
},
|
||
|
{
|
||
|
signingDate,
|
||
|
signingRegion,
|
||
|
signingService,
|
||
|
priorSignature: signableMessage.priorSignature
|
||
|
}
|
||
|
);
|
||
|
return promise.then((signature) => {
|
||
|
return { message: signableMessage.message, signature };
|
||
|
});
|
||
|
}
|
||
|
async signString(stringToSign, { signingDate = /* @__PURE__ */ new Date(), signingRegion, signingService } = {}) {
|
||
|
const credentials = await this.credentialProvider();
|
||
|
this.validateResolvedCredentials(credentials);
|
||
|
const region = signingRegion ?? await this.regionProvider();
|
||
|
const { shortDate } = formatDate(signingDate);
|
||
|
const hash = new this.sha256(await this.getSigningKey(credentials, region, shortDate, signingService));
|
||
|
hash.update((0, import_util_utf84.toUint8Array)(stringToSign));
|
||
|
return (0, import_util_hex_encoding.toHex)(await hash.digest());
|
||
|
}
|
||
|
async signRequest(requestToSign, {
|
||
|
signingDate = /* @__PURE__ */ new Date(),
|
||
|
signableHeaders,
|
||
|
unsignableHeaders,
|
||
|
signingRegion,
|
||
|
signingService
|
||
|
} = {}) {
|
||
|
const credentials = await this.credentialProvider();
|
||
|
this.validateResolvedCredentials(credentials);
|
||
|
const region = signingRegion ?? await this.regionProvider();
|
||
|
const request = prepareRequest(requestToSign);
|
||
|
const { longDate, shortDate } = formatDate(signingDate);
|
||
|
const scope = createScope(shortDate, region, signingService ?? this.service);
|
||
|
request.headers[AMZ_DATE_HEADER] = longDate;
|
||
|
if (credentials.sessionToken) {
|
||
|
request.headers[TOKEN_HEADER] = credentials.sessionToken;
|
||
|
}
|
||
|
const payloadHash = await getPayloadHash(request, this.sha256);
|
||
|
if (!hasHeader(SHA256_HEADER, request.headers) && this.applyChecksum) {
|
||
|
request.headers[SHA256_HEADER] = payloadHash;
|
||
|
}
|
||
|
const canonicalHeaders = getCanonicalHeaders(request, unsignableHeaders, signableHeaders);
|
||
|
const signature = await this.getSignature(
|
||
|
longDate,
|
||
|
scope,
|
||
|
this.getSigningKey(credentials, region, shortDate, signingService),
|
||
|
this.createCanonicalRequest(request, canonicalHeaders, payloadHash)
|
||
|
);
|
||
|
request.headers[AUTH_HEADER] = `${ALGORITHM_IDENTIFIER} Credential=${credentials.accessKeyId}/${scope}, SignedHeaders=${getCanonicalHeaderList(canonicalHeaders)}, Signature=${signature}`;
|
||
|
return request;
|
||
|
}
|
||
|
createCanonicalRequest(request, canonicalHeaders, payloadHash) {
|
||
|
const sortedHeaders = Object.keys(canonicalHeaders).sort();
|
||
|
return `${request.method}
|
||
|
${this.getCanonicalPath(request)}
|
||
|
${getCanonicalQuery(request)}
|
||
|
${sortedHeaders.map((name) => `${name}:${canonicalHeaders[name]}`).join("\n")}
|
||
|
|
||
|
${sortedHeaders.join(";")}
|
||
|
${payloadHash}`;
|
||
|
}
|
||
|
async createStringToSign(longDate, credentialScope, canonicalRequest) {
|
||
|
const hash = new this.sha256();
|
||
|
hash.update((0, import_util_utf84.toUint8Array)(canonicalRequest));
|
||
|
const hashedRequest = await hash.digest();
|
||
|
return `${ALGORITHM_IDENTIFIER}
|
||
|
${longDate}
|
||
|
${credentialScope}
|
||
|
${(0, import_util_hex_encoding.toHex)(hashedRequest)}`;
|
||
|
}
|
||
|
getCanonicalPath({ path }) {
|
||
|
if (this.uriEscapePath) {
|
||
|
const normalizedPathSegments = [];
|
||
|
for (const pathSegment of path.split("/")) {
|
||
|
if ((pathSegment == null ? void 0 : pathSegment.length) === 0)
|
||
|
continue;
|
||
|
if (pathSegment === ".")
|
||
|
continue;
|
||
|
if (pathSegment === "..") {
|
||
|
normalizedPathSegments.pop();
|
||
|
} else {
|
||
|
normalizedPathSegments.push(pathSegment);
|
||
|
}
|
||
|
}
|
||
|
const normalizedPath = `${(path == null ? void 0 : path.startsWith("/")) ? "/" : ""}${normalizedPathSegments.join("/")}${normalizedPathSegments.length > 0 && (path == null ? void 0 : path.endsWith("/")) ? "/" : ""}`;
|
||
|
const doubleEncoded = (0, import_util_uri_escape.escapeUri)(normalizedPath);
|
||
|
return doubleEncoded.replace(/%2F/g, "/");
|
||
|
}
|
||
|
return path;
|
||
|
}
|
||
|
async getSignature(longDate, credentialScope, keyPromise, canonicalRequest) {
|
||
|
const stringToSign = await this.createStringToSign(longDate, credentialScope, canonicalRequest);
|
||
|
const hash = new this.sha256(await keyPromise);
|
||
|
hash.update((0, import_util_utf84.toUint8Array)(stringToSign));
|
||
|
return (0, import_util_hex_encoding.toHex)(await hash.digest());
|
||
|
}
|
||
|
getSigningKey(credentials, region, shortDate, service) {
|
||
|
return getSigningKey(this.sha256, credentials, shortDate, region, service || this.service);
|
||
|
}
|
||
|
validateResolvedCredentials(credentials) {
|
||
|
if (typeof credentials !== "object" || // @ts-expect-error: Property 'accessKeyId' does not exist on type 'object'.ts(2339)
|
||
|
typeof credentials.accessKeyId !== "string" || // @ts-expect-error: Property 'secretAccessKey' does not exist on type 'object'.ts(2339)
|
||
|
typeof credentials.secretAccessKey !== "string") {
|
||
|
throw new Error("Resolved credential object is not valid");
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
__name(_SignatureV4, "SignatureV4");
|
||
|
var SignatureV4 = _SignatureV4;
|
||
|
var formatDate = /* @__PURE__ */ __name((now) => {
|
||
|
const longDate = iso8601(now).replace(/[\-:]/g, "");
|
||
|
return {
|
||
|
longDate,
|
||
|
shortDate: longDate.slice(0, 8)
|
||
|
};
|
||
|
}, "formatDate");
|
||
|
var getCanonicalHeaderList = /* @__PURE__ */ __name((headers) => Object.keys(headers).sort().join(";"), "getCanonicalHeaderList");
|
||
|
// Annotate the CommonJS export names for ESM import in node:
|
||
|
|
||
|
0 && (module.exports = {
|
||
|
getCanonicalHeaders,
|
||
|
getCanonicalQuery,
|
||
|
getPayloadHash,
|
||
|
moveHeadersToQuery,
|
||
|
prepareRequest,
|
||
|
SignatureV4,
|
||
|
createScope,
|
||
|
getSigningKey,
|
||
|
clearCredentialCache
|
||
|
});
|
||
|
|