@contember/engine-s3-plugin 1.4.0-rc.7 → 2.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/development/index.cjs +30 -0
- package/dist/development/index.cjs.map +1 -0
- package/dist/development/index.js +31 -0
- package/dist/development/index.js.map +1 -0
- package/dist/development/src/Config.cjs +73 -0
- package/dist/development/src/Config.cjs.map +1 -0
- package/dist/development/src/Config.js +56 -0
- package/dist/development/src/Config.js.map +1 -0
- package/dist/development/src/S3ConfigProcessor.cjs +60 -0
- package/dist/development/src/S3ConfigProcessor.cjs.map +1 -0
- package/dist/development/src/S3ConfigProcessor.js +43 -0
- package/dist/development/src/S3ConfigProcessor.js.map +1 -0
- package/dist/development/src/S3ObjectAuthorizator.cjs +46 -0
- package/dist/development/src/S3ObjectAuthorizator.cjs.map +1 -0
- package/dist/development/src/S3ObjectAuthorizator.js +46 -0
- package/dist/development/src/S3ObjectAuthorizator.js.map +1 -0
- package/dist/development/src/S3SchemaContributor.cjs +97 -0
- package/dist/development/src/S3SchemaContributor.cjs.map +1 -0
- package/dist/development/src/S3SchemaContributor.js +97 -0
- package/dist/development/src/S3SchemaContributor.js.map +1 -0
- package/dist/development/src/S3SchemaTypes.cjs +71 -0
- package/dist/development/src/S3SchemaTypes.cjs.map +1 -0
- package/dist/development/src/S3SchemaTypes.js +71 -0
- package/dist/development/src/S3SchemaTypes.js.map +1 -0
- package/dist/development/src/S3Service.cjs +105 -0
- package/dist/development/src/S3Service.cjs.map +1 -0
- package/dist/development/src/S3Service.js +105 -0
- package/dist/development/src/S3Service.js.map +1 -0
- package/dist/development/src/S3Signer.cjs +84 -0
- package/dist/development/src/S3Signer.cjs.map +1 -0
- package/dist/development/src/S3Signer.js +84 -0
- package/dist/development/src/S3Signer.js.map +1 -0
- package/dist/production/index.cjs +30 -0
- package/dist/production/index.cjs.map +1 -0
- package/dist/production/index.js +31 -0
- package/dist/production/index.js.map +1 -0
- package/dist/production/src/Config.cjs +73 -0
- package/dist/production/src/Config.cjs.map +1 -0
- package/dist/production/src/Config.js +56 -0
- package/dist/production/src/Config.js.map +1 -0
- package/dist/production/src/S3ConfigProcessor.cjs +60 -0
- package/dist/production/src/S3ConfigProcessor.cjs.map +1 -0
- package/dist/production/src/S3ConfigProcessor.js +43 -0
- package/dist/production/src/S3ConfigProcessor.js.map +1 -0
- package/dist/production/src/S3ObjectAuthorizator.cjs +46 -0
- package/dist/production/src/S3ObjectAuthorizator.cjs.map +1 -0
- package/dist/production/src/S3ObjectAuthorizator.js +46 -0
- package/dist/production/src/S3ObjectAuthorizator.js.map +1 -0
- package/dist/production/src/S3SchemaContributor.cjs +97 -0
- package/dist/production/src/S3SchemaContributor.cjs.map +1 -0
- package/dist/production/src/S3SchemaContributor.js +97 -0
- package/dist/production/src/S3SchemaContributor.js.map +1 -0
- package/dist/production/src/S3SchemaTypes.cjs +71 -0
- package/dist/production/src/S3SchemaTypes.cjs.map +1 -0
- package/dist/production/src/S3SchemaTypes.js +71 -0
- package/dist/production/src/S3SchemaTypes.js.map +1 -0
- package/dist/production/src/S3Service.cjs +105 -0
- package/dist/production/src/S3Service.cjs.map +1 -0
- package/dist/production/src/S3Service.js +105 -0
- package/dist/production/src/S3Service.js.map +1 -0
- package/dist/production/src/S3Signer.cjs +84 -0
- package/dist/production/src/S3Signer.cjs.map +1 -0
- package/dist/production/src/S3Signer.js +84 -0
- package/dist/production/src/S3Signer.js.map +1 -0
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/{src → types}/Config.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +24 -12
- package/src/tsconfig.json +1 -1
- package/tests/cases/signRequest.test.ts +1 -1
- package/vitest.config.ts +3 -0
- package/dist/src/Config.js +0 -75
- package/dist/src/Config.js.map +0 -1
- package/dist/src/S3ConfigProcessor.js +0 -64
- package/dist/src/S3ConfigProcessor.js.map +0 -1
- package/dist/src/S3ObjectAuthorizator.js +0 -48
- package/dist/src/S3ObjectAuthorizator.js.map +0 -1
- package/dist/src/S3SchemaContributor.js +0 -122
- package/dist/src/S3SchemaContributor.js.map +0 -1
- package/dist/src/S3SchemaTypes.js +0 -65
- package/dist/src/S3SchemaTypes.js.map +0 -1
- package/dist/src/S3Service.js +0 -101
- package/dist/src/S3Service.js.map +0 -1
- package/dist/src/S3Signer.js +0 -92
- package/dist/src/S3Signer.js.map +0 -1
- package/dist/src/index.js +0 -39
- package/dist/src/index.js.map +0 -1
- package/dist/src/tsconfig.tsbuildinfo +0 -1
- package/dist/tests/cases/authorizator.test.js +0 -21
- package/dist/tests/cases/authorizator.test.js.map +0 -1
- package/dist/tests/cases/signRequest.test.js +0 -44
- package/dist/tests/cases/signRequest.test.js.map +0 -1
- package/vite.config.js +0 -3
- /package/dist/{src → types}/Config.d.ts +0 -0
- /package/dist/{src → types}/S3ConfigProcessor.d.ts +0 -0
- /package/dist/{src → types}/S3ConfigProcessor.d.ts.map +0 -0
- /package/dist/{src → types}/S3ObjectAuthorizator.d.ts +0 -0
- /package/dist/{src → types}/S3ObjectAuthorizator.d.ts.map +0 -0
- /package/dist/{src → types}/S3SchemaContributor.d.ts +0 -0
- /package/dist/{src → types}/S3SchemaContributor.d.ts.map +0 -0
- /package/dist/{src → types}/S3SchemaTypes.d.ts +0 -0
- /package/dist/{src → types}/S3SchemaTypes.d.ts.map +0 -0
- /package/dist/{src → types}/S3Service.d.ts +0 -0
- /package/dist/{src → types}/S3Service.d.ts.map +0 -0
- /package/dist/{src → types}/S3Signer.d.ts +0 -0
- /package/dist/{src → types}/S3Signer.d.ts.map +0 -0
- /package/dist/{src → types}/index.d.ts +0 -0
- /package/dist/{src → types}/index.d.ts.map +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"S3Signer.cjs","sources":["../../../../packages/engine-s3-plugin/src/S3Signer.ts"],"sourcesContent":["import { resolveS3Endpoint, S3Config } from './Config'\nimport { Providers } from '@contember/engine-plugins'\nimport qs from 'qs'\nimport { BinaryLike, createHash, createHmac } from 'node:crypto'\n\ninterface S3Request {\n\taction: 'read' | 'upload'\n\tkey: string\n\texpiration: number\n\theaders: Record<string, string>\n}\n\nconst hmac = (secret: BinaryLike, data: BinaryLike) => createHmac('sha256', secret).update(data).digest()\n\nconst hash = (data: BinaryLike) => createHash('sha256').update(data).digest('hex')\n\nconst unsignableHeaders = ['authorization', 'user-agent', 'content-type', 'expect', 'x-amzn-trace-id']\n\nconst sortMap = <T extends Record<string, any>>(input: T): T => {\n\treturn Object.fromEntries(Object.entries(input).sort((a, b) => (a[0] < b[0] ? -1 : 1))) as T\n}\nexport class S3Signer {\n\tprivate region: string\n\n\tconstructor(private readonly config: S3Config, private readonly providers: Pick<Providers, 'now'>) {\n\t\tthis.region = config.region || 'eu-west-1'\n\t}\n\n\tpublic sign(request: S3Request) {\n\t\tconst uris = resolveS3Endpoint(this.config)\n\t\trequest.headers.host = uris.endpoint.substring(uris.endpoint.indexOf('://') + 3)\n\t\tconst nowFormatted = this.providers\n\t\t\t.now()\n\t\t\t.toISOString()\n\t\t\t.replace(/[:\\-]|\\.\\d{3}/g, '')\n\t\tconst queryString = this.getQueryParams(request, nowFormatted)\n\t\tconst path = uris.basePath + '/' + request.key\n\t\tconst lines = [\n\t\t\trequest.action === 'read' ? 'GET' : 'PUT',\n\t\t\tpath,\n\t\t\tqueryString,\n\t\t\tthis.getSignedHeaders(request),\n\t\t\tthis.getSignedHeaderNames(Object.keys(request.headers)),\n\t\t\t'UNSIGNED-PAYLOAD',\n\t\t]\n\t\tconst canonicalRequest = lines.join('\\n')\n\n\t\tconst parts = ['AWS4-HMAC-SHA256', nowFormatted, this.getScope(nowFormatted), hash(canonicalRequest)]\n\n\t\tconst signature = [nowFormatted.substring(0, 8), this.region, 's3', 'aws4_request', parts.join('\\n')]\n\t\t\t.reduce((acc, x) => hmac(acc, x), Buffer.from('AWS4' + this.config.credentials.secret))\n\t\t\t.toString('hex')\n\t\treturn uris.endpoint + path + '?' + (queryString + '&X-Amz-Signature=' + signature).split('&').sort().join('&')\n\t}\n\n\tprivate getQueryParams(request: S3Request, dateFormatted: string) {\n\t\tconst scope = this.getScope(dateFormatted)\n\t\tconst queryString: Record<string, string> = {\n\t\t\t'X-Amz-Date': dateFormatted,\n\t\t\t'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',\n\t\t\t'X-Amz-Credential': this.config.credentials.key + '/' + scope,\n\t\t\t'X-Amz-Expires': String(request.expiration),\n\t\t\t'X-Amz-SignedHeaders': this.getSignedHeaderNames(Object.keys(request.headers)),\n\t\t}\n\n\t\tconst headersToQs = ['content-type', 'content-md5', 'cache-control']\n\t\tfor (const header in request.headers) {\n\t\t\tconst headerLc = header.toLowerCase()\n\t\t\tif (headersToQs.includes(headerLc) || headerLc.startsWith('x-amz-')) {\n\t\t\t\tqueryString[headerLc.startsWith('x-amz-meta-') ? headerLc : header] = request.headers[header]\n\t\t\t}\n\t\t}\n\t\tconst qsSorted = sortMap(queryString)\n\t\treturn qs.stringify(qsSorted)\n\t}\n\n\tprivate getScope(dateFormatted: string) {\n\t\treturn dateFormatted.substring(0, 8) + '/' + this.region + '/s3/aws4_request'\n\t}\n\n\tprivate getSignedHeaders(request: S3Request): string {\n\t\tconst lines = []\n\t\tfor (const header in request.headers) {\n\t\t\tconst headerNameLc = header.toLowerCase()\n\t\t\tif (!this.isHeaderSignable(headerNameLc)) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst value = request.headers[header].replace(/\\s+/g, ' ').replace(/^\\s+|\\s+$/g, '')\n\t\t\tlines.push(`${headerNameLc}:${value}\\n`)\n\t\t}\n\t\treturn lines.sort().join('')\n\t}\n\n\tprivate isHeaderSignable(headerName: string) {\n\t\treturn headerName.toLowerCase().startsWith('x-amz') || !unsignableHeaders.includes(headerName.toLowerCase())\n\t}\n\n\tprivate getSignedHeaderNames(headers: string[]) {\n\t\treturn headers\n\t\t\t.map(it => it.toLowerCase())\n\t\t\t.filter(this.isHeaderSignable)\n\t\t\t.sort()\n\t\t\t.join(';')\n\t}\n}\n"],"names":["createHmac","createHash","resolveS3Endpoint"],"mappings":";;;;;;;;AAYA,MAAM,OAAO,CAAC,QAAoB,SAAqBA,kBAAW,UAAU,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO;AAExG,MAAM,OAAO,CAAC,SAAqBC,OAAAA,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK;AAEjF,MAAM,oBAAoB,CAAC,iBAAiB,cAAc,gBAAgB,UAAU,iBAAiB;AAErG,MAAM,UAAU,CAAgC,UAAgB;AAC/D,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,KAAK,CAAC,GAAG,MAAO,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAE,CAAC;AACvF;AACO,MAAM,SAAS;AAAA,EAGrB,YAA6B,QAAmC,WAAmC;AAAtE,SAAA,SAAA;AAAmC,SAAA,YAAA;AAFxD,kBAAA,MAAA,QAAA;AAGF,SAAA,SAAS,OAAO,UAAU;AAAA,EAChC;AAAA,EAEO,KAAK,SAAoB;AACzB,UAAA,OAAOC,OAAAA,kBAAkB,KAAK,MAAM;AAClC,YAAA,QAAQ,OAAO,KAAK,SAAS,UAAU,KAAK,SAAS,QAAQ,KAAK,IAAI,CAAC;AACzE,UAAA,eAAe,KAAK,UACxB,IAAA,EACA,YAAY,EACZ,QAAQ,kBAAkB,EAAE;AAC9B,UAAM,cAAc,KAAK,eAAe,SAAS,YAAY;AAC7D,UAAM,OAAO,KAAK,WAAW,MAAM,QAAQ;AAC3C,UAAM,QAAQ;AAAA,MACb,QAAQ,WAAW,SAAS,QAAQ;AAAA,MACpC;AAAA,MACA;AAAA,MACA,KAAK,iBAAiB,OAAO;AAAA,MAC7B,KAAK,qBAAqB,OAAO,KAAK,QAAQ,OAAO,CAAC;AAAA,MACtD;AAAA,IAAA;AAEK,UAAA,mBAAmB,MAAM,KAAK,IAAI;AAElC,UAAA,QAAQ,CAAC,oBAAoB,cAAc,KAAK,SAAS,YAAY,GAAG,KAAK,gBAAgB,CAAC;AAEpG,UAAM,YAAY,CAAC,aAAa,UAAU,GAAG,CAAC,GAAG,KAAK,QAAQ,MAAM,gBAAgB,MAAM,KAAK,IAAI,CAAC,EAClG,OAAO,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,GAAG,OAAO,KAAK,SAAS,KAAK,OAAO,YAAY,MAAM,CAAC,EACrF,SAAS,KAAK;AAChB,WAAO,KAAK,WAAW,OAAO,OAAO,cAAc,sBAAsB,WAAW,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG;AAAA,EAC/G;AAAA,EAEQ,eAAe,SAAoB,eAAuB;AAC3D,UAAA,QAAQ,KAAK,SAAS,aAAa;AACzC,UAAM,cAAsC;AAAA,MAC3C,cAAc;AAAA,MACd,mBAAmB;AAAA,MACnB,oBAAoB,KAAK,OAAO,YAAY,MAAM,MAAM;AAAA,MACxD,iBAAiB,OAAO,QAAQ,UAAU;AAAA,MAC1C,uBAAuB,KAAK,qBAAqB,OAAO,KAAK,QAAQ,OAAO,CAAC;AAAA,IAAA;AAG9E,UAAM,cAAc,CAAC,gBAAgB,eAAe,eAAe;AACxD,eAAA,UAAU,QAAQ,SAAS;AAC/B,YAAA,WAAW,OAAO;AACxB,UAAI,YAAY,SAAS,QAAQ,KAAK,SAAS,WAAW,QAAQ,GAAG;AACxD,oBAAA,SAAS,WAAW,aAAa,IAAI,WAAW,MAAM,IAAI,QAAQ,QAAQ,MAAM;AAAA,MAC7F;AAAA,IACD;AACM,UAAA,WAAW,QAAQ,WAAW;AAC7B,WAAA,GAAG,UAAU,QAAQ;AAAA,EAC7B;AAAA,EAEQ,SAAS,eAAuB;AACvC,WAAO,cAAc,UAAU,GAAG,CAAC,IAAI,MAAM,KAAK,SAAS;AAAA,EAC5D;AAAA,EAEQ,iBAAiB,SAA4B;AACpD,UAAM,QAAQ,CAAA;AACH,eAAA,UAAU,QAAQ,SAAS;AAC/B,YAAA,eAAe,OAAO;AAC5B,UAAI,CAAC,KAAK,iBAAiB,YAAY,GAAG;AACzC;AAAA,MACD;AACM,YAAA,QAAQ,QAAQ,QAAQ,MAAM,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,cAAc,EAAE;AACnF,YAAM,KAAK,GAAG,YAAY,IAAI,KAAK;AAAA,CAAI;AAAA,IACxC;AACA,WAAO,MAAM,KAAA,EAAO,KAAK,EAAE;AAAA,EAC5B;AAAA,EAEQ,iBAAiB,YAAoB;AACrC,WAAA,WAAW,cAAc,WAAW,OAAO,KAAK,CAAC,kBAAkB,SAAS,WAAW,YAAa,CAAA;AAAA,EAC5G;AAAA,EAEQ,qBAAqB,SAAmB;AAC/C,WAAO,QACL,IAAI,CAAM,OAAA,GAAG,aAAa,EAC1B,OAAO,KAAK,gBAAgB,EAC5B,KAAK,EACL,KAAK,GAAG;AAAA,EACX;AACD;;"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { resolveS3Endpoint } from "./Config.js";
|
|
2
|
+
import qs from "qs";
|
|
3
|
+
import { createHmac, createHash } from "node:crypto";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, key + "", value);
|
|
7
|
+
const hmac = (secret, data) => createHmac("sha256", secret).update(data).digest();
|
|
8
|
+
const hash = (data) => createHash("sha256").update(data).digest("hex");
|
|
9
|
+
const unsignableHeaders = ["authorization", "user-agent", "content-type", "expect", "x-amzn-trace-id"];
|
|
10
|
+
const sortMap = (input) => {
|
|
11
|
+
return Object.fromEntries(Object.entries(input).sort((a, b) => a[0] < b[0] ? -1 : 1));
|
|
12
|
+
};
|
|
13
|
+
class S3Signer {
|
|
14
|
+
constructor(config, providers) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.providers = providers;
|
|
17
|
+
__publicField(this, "region");
|
|
18
|
+
this.region = config.region || "eu-west-1";
|
|
19
|
+
}
|
|
20
|
+
sign(request) {
|
|
21
|
+
const uris = resolveS3Endpoint(this.config);
|
|
22
|
+
request.headers.host = uris.endpoint.substring(uris.endpoint.indexOf("://") + 3);
|
|
23
|
+
const nowFormatted = this.providers.now().toISOString().replace(/[:\-]|\.\d{3}/g, "");
|
|
24
|
+
const queryString = this.getQueryParams(request, nowFormatted);
|
|
25
|
+
const path = uris.basePath + "/" + request.key;
|
|
26
|
+
const lines = [
|
|
27
|
+
request.action === "read" ? "GET" : "PUT",
|
|
28
|
+
path,
|
|
29
|
+
queryString,
|
|
30
|
+
this.getSignedHeaders(request),
|
|
31
|
+
this.getSignedHeaderNames(Object.keys(request.headers)),
|
|
32
|
+
"UNSIGNED-PAYLOAD"
|
|
33
|
+
];
|
|
34
|
+
const canonicalRequest = lines.join("\n");
|
|
35
|
+
const parts = ["AWS4-HMAC-SHA256", nowFormatted, this.getScope(nowFormatted), hash(canonicalRequest)];
|
|
36
|
+
const signature = [nowFormatted.substring(0, 8), this.region, "s3", "aws4_request", parts.join("\n")].reduce((acc, x) => hmac(acc, x), Buffer.from("AWS4" + this.config.credentials.secret)).toString("hex");
|
|
37
|
+
return uris.endpoint + path + "?" + (queryString + "&X-Amz-Signature=" + signature).split("&").sort().join("&");
|
|
38
|
+
}
|
|
39
|
+
getQueryParams(request, dateFormatted) {
|
|
40
|
+
const scope = this.getScope(dateFormatted);
|
|
41
|
+
const queryString = {
|
|
42
|
+
"X-Amz-Date": dateFormatted,
|
|
43
|
+
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
|
|
44
|
+
"X-Amz-Credential": this.config.credentials.key + "/" + scope,
|
|
45
|
+
"X-Amz-Expires": String(request.expiration),
|
|
46
|
+
"X-Amz-SignedHeaders": this.getSignedHeaderNames(Object.keys(request.headers))
|
|
47
|
+
};
|
|
48
|
+
const headersToQs = ["content-type", "content-md5", "cache-control"];
|
|
49
|
+
for (const header in request.headers) {
|
|
50
|
+
const headerLc = header.toLowerCase();
|
|
51
|
+
if (headersToQs.includes(headerLc) || headerLc.startsWith("x-amz-")) {
|
|
52
|
+
queryString[headerLc.startsWith("x-amz-meta-") ? headerLc : header] = request.headers[header];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const qsSorted = sortMap(queryString);
|
|
56
|
+
return qs.stringify(qsSorted);
|
|
57
|
+
}
|
|
58
|
+
getScope(dateFormatted) {
|
|
59
|
+
return dateFormatted.substring(0, 8) + "/" + this.region + "/s3/aws4_request";
|
|
60
|
+
}
|
|
61
|
+
getSignedHeaders(request) {
|
|
62
|
+
const lines = [];
|
|
63
|
+
for (const header in request.headers) {
|
|
64
|
+
const headerNameLc = header.toLowerCase();
|
|
65
|
+
if (!this.isHeaderSignable(headerNameLc)) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const value = request.headers[header].replace(/\s+/g, " ").replace(/^\s+|\s+$/g, "");
|
|
69
|
+
lines.push(`${headerNameLc}:${value}
|
|
70
|
+
`);
|
|
71
|
+
}
|
|
72
|
+
return lines.sort().join("");
|
|
73
|
+
}
|
|
74
|
+
isHeaderSignable(headerName) {
|
|
75
|
+
return headerName.toLowerCase().startsWith("x-amz") || !unsignableHeaders.includes(headerName.toLowerCase());
|
|
76
|
+
}
|
|
77
|
+
getSignedHeaderNames(headers) {
|
|
78
|
+
return headers.map((it) => it.toLowerCase()).filter(this.isHeaderSignable).sort().join(";");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
S3Signer
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=S3Signer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"S3Signer.js","sources":["../../../../packages/engine-s3-plugin/src/S3Signer.ts"],"sourcesContent":["import { resolveS3Endpoint, S3Config } from './Config'\nimport { Providers } from '@contember/engine-plugins'\nimport qs from 'qs'\nimport { BinaryLike, createHash, createHmac } from 'node:crypto'\n\ninterface S3Request {\n\taction: 'read' | 'upload'\n\tkey: string\n\texpiration: number\n\theaders: Record<string, string>\n}\n\nconst hmac = (secret: BinaryLike, data: BinaryLike) => createHmac('sha256', secret).update(data).digest()\n\nconst hash = (data: BinaryLike) => createHash('sha256').update(data).digest('hex')\n\nconst unsignableHeaders = ['authorization', 'user-agent', 'content-type', 'expect', 'x-amzn-trace-id']\n\nconst sortMap = <T extends Record<string, any>>(input: T): T => {\n\treturn Object.fromEntries(Object.entries(input).sort((a, b) => (a[0] < b[0] ? -1 : 1))) as T\n}\nexport class S3Signer {\n\tprivate region: string\n\n\tconstructor(private readonly config: S3Config, private readonly providers: Pick<Providers, 'now'>) {\n\t\tthis.region = config.region || 'eu-west-1'\n\t}\n\n\tpublic sign(request: S3Request) {\n\t\tconst uris = resolveS3Endpoint(this.config)\n\t\trequest.headers.host = uris.endpoint.substring(uris.endpoint.indexOf('://') + 3)\n\t\tconst nowFormatted = this.providers\n\t\t\t.now()\n\t\t\t.toISOString()\n\t\t\t.replace(/[:\\-]|\\.\\d{3}/g, '')\n\t\tconst queryString = this.getQueryParams(request, nowFormatted)\n\t\tconst path = uris.basePath + '/' + request.key\n\t\tconst lines = [\n\t\t\trequest.action === 'read' ? 'GET' : 'PUT',\n\t\t\tpath,\n\t\t\tqueryString,\n\t\t\tthis.getSignedHeaders(request),\n\t\t\tthis.getSignedHeaderNames(Object.keys(request.headers)),\n\t\t\t'UNSIGNED-PAYLOAD',\n\t\t]\n\t\tconst canonicalRequest = lines.join('\\n')\n\n\t\tconst parts = ['AWS4-HMAC-SHA256', nowFormatted, this.getScope(nowFormatted), hash(canonicalRequest)]\n\n\t\tconst signature = [nowFormatted.substring(0, 8), this.region, 's3', 'aws4_request', parts.join('\\n')]\n\t\t\t.reduce((acc, x) => hmac(acc, x), Buffer.from('AWS4' + this.config.credentials.secret))\n\t\t\t.toString('hex')\n\t\treturn uris.endpoint + path + '?' + (queryString + '&X-Amz-Signature=' + signature).split('&').sort().join('&')\n\t}\n\n\tprivate getQueryParams(request: S3Request, dateFormatted: string) {\n\t\tconst scope = this.getScope(dateFormatted)\n\t\tconst queryString: Record<string, string> = {\n\t\t\t'X-Amz-Date': dateFormatted,\n\t\t\t'X-Amz-Algorithm': 'AWS4-HMAC-SHA256',\n\t\t\t'X-Amz-Credential': this.config.credentials.key + '/' + scope,\n\t\t\t'X-Amz-Expires': String(request.expiration),\n\t\t\t'X-Amz-SignedHeaders': this.getSignedHeaderNames(Object.keys(request.headers)),\n\t\t}\n\n\t\tconst headersToQs = ['content-type', 'content-md5', 'cache-control']\n\t\tfor (const header in request.headers) {\n\t\t\tconst headerLc = header.toLowerCase()\n\t\t\tif (headersToQs.includes(headerLc) || headerLc.startsWith('x-amz-')) {\n\t\t\t\tqueryString[headerLc.startsWith('x-amz-meta-') ? headerLc : header] = request.headers[header]\n\t\t\t}\n\t\t}\n\t\tconst qsSorted = sortMap(queryString)\n\t\treturn qs.stringify(qsSorted)\n\t}\n\n\tprivate getScope(dateFormatted: string) {\n\t\treturn dateFormatted.substring(0, 8) + '/' + this.region + '/s3/aws4_request'\n\t}\n\n\tprivate getSignedHeaders(request: S3Request): string {\n\t\tconst lines = []\n\t\tfor (const header in request.headers) {\n\t\t\tconst headerNameLc = header.toLowerCase()\n\t\t\tif (!this.isHeaderSignable(headerNameLc)) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst value = request.headers[header].replace(/\\s+/g, ' ').replace(/^\\s+|\\s+$/g, '')\n\t\t\tlines.push(`${headerNameLc}:${value}\\n`)\n\t\t}\n\t\treturn lines.sort().join('')\n\t}\n\n\tprivate isHeaderSignable(headerName: string) {\n\t\treturn headerName.toLowerCase().startsWith('x-amz') || !unsignableHeaders.includes(headerName.toLowerCase())\n\t}\n\n\tprivate getSignedHeaderNames(headers: string[]) {\n\t\treturn headers\n\t\t\t.map(it => it.toLowerCase())\n\t\t\t.filter(this.isHeaderSignable)\n\t\t\t.sort()\n\t\t\t.join(';')\n\t}\n}\n"],"names":[],"mappings":";;;;;;AAYA,MAAM,OAAO,CAAC,QAAoB,SAAqB,WAAW,UAAU,MAAM,EAAE,OAAO,IAAI,EAAE,OAAO;AAExG,MAAM,OAAO,CAAC,SAAqB,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK;AAEjF,MAAM,oBAAoB,CAAC,iBAAiB,cAAc,gBAAgB,UAAU,iBAAiB;AAErG,MAAM,UAAU,CAAgC,UAAgB;AAC/D,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,KAAK,CAAC,GAAG,MAAO,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAE,CAAC;AACvF;AACO,MAAM,SAAS;AAAA,EAGrB,YAA6B,QAAmC,WAAmC;AAAtE,SAAA,SAAA;AAAmC,SAAA,YAAA;AAFxD,kBAAA,MAAA,QAAA;AAGF,SAAA,SAAS,OAAO,UAAU;AAAA,EAChC;AAAA,EAEO,KAAK,SAAoB;AACzB,UAAA,OAAO,kBAAkB,KAAK,MAAM;AAClC,YAAA,QAAQ,OAAO,KAAK,SAAS,UAAU,KAAK,SAAS,QAAQ,KAAK,IAAI,CAAC;AACzE,UAAA,eAAe,KAAK,UACxB,IAAA,EACA,YAAY,EACZ,QAAQ,kBAAkB,EAAE;AAC9B,UAAM,cAAc,KAAK,eAAe,SAAS,YAAY;AAC7D,UAAM,OAAO,KAAK,WAAW,MAAM,QAAQ;AAC3C,UAAM,QAAQ;AAAA,MACb,QAAQ,WAAW,SAAS,QAAQ;AAAA,MACpC;AAAA,MACA;AAAA,MACA,KAAK,iBAAiB,OAAO;AAAA,MAC7B,KAAK,qBAAqB,OAAO,KAAK,QAAQ,OAAO,CAAC;AAAA,MACtD;AAAA,IAAA;AAEK,UAAA,mBAAmB,MAAM,KAAK,IAAI;AAElC,UAAA,QAAQ,CAAC,oBAAoB,cAAc,KAAK,SAAS,YAAY,GAAG,KAAK,gBAAgB,CAAC;AAEpG,UAAM,YAAY,CAAC,aAAa,UAAU,GAAG,CAAC,GAAG,KAAK,QAAQ,MAAM,gBAAgB,MAAM,KAAK,IAAI,CAAC,EAClG,OAAO,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,GAAG,OAAO,KAAK,SAAS,KAAK,OAAO,YAAY,MAAM,CAAC,EACrF,SAAS,KAAK;AAChB,WAAO,KAAK,WAAW,OAAO,OAAO,cAAc,sBAAsB,WAAW,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG;AAAA,EAC/G;AAAA,EAEQ,eAAe,SAAoB,eAAuB;AAC3D,UAAA,QAAQ,KAAK,SAAS,aAAa;AACzC,UAAM,cAAsC;AAAA,MAC3C,cAAc;AAAA,MACd,mBAAmB;AAAA,MACnB,oBAAoB,KAAK,OAAO,YAAY,MAAM,MAAM;AAAA,MACxD,iBAAiB,OAAO,QAAQ,UAAU;AAAA,MAC1C,uBAAuB,KAAK,qBAAqB,OAAO,KAAK,QAAQ,OAAO,CAAC;AAAA,IAAA;AAG9E,UAAM,cAAc,CAAC,gBAAgB,eAAe,eAAe;AACxD,eAAA,UAAU,QAAQ,SAAS;AAC/B,YAAA,WAAW,OAAO;AACxB,UAAI,YAAY,SAAS,QAAQ,KAAK,SAAS,WAAW,QAAQ,GAAG;AACxD,oBAAA,SAAS,WAAW,aAAa,IAAI,WAAW,MAAM,IAAI,QAAQ,QAAQ,MAAM;AAAA,MAC7F;AAAA,IACD;AACM,UAAA,WAAW,QAAQ,WAAW;AAC7B,WAAA,GAAG,UAAU,QAAQ;AAAA,EAC7B;AAAA,EAEQ,SAAS,eAAuB;AACvC,WAAO,cAAc,UAAU,GAAG,CAAC,IAAI,MAAM,KAAK,SAAS;AAAA,EAC5D;AAAA,EAEQ,iBAAiB,SAA4B;AACpD,UAAM,QAAQ,CAAA;AACH,eAAA,UAAU,QAAQ,SAAS;AAC/B,YAAA,eAAe,OAAO;AAC5B,UAAI,CAAC,KAAK,iBAAiB,YAAY,GAAG;AACzC;AAAA,MACD;AACM,YAAA,QAAQ,QAAQ,QAAQ,MAAM,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,cAAc,EAAE;AACnF,YAAM,KAAK,GAAG,YAAY,IAAI,KAAK;AAAA,CAAI;AAAA,IACxC;AACA,WAAO,MAAM,KAAA,EAAO,KAAK,EAAE;AAAA,EAC5B;AAAA,EAEQ,iBAAiB,YAAoB;AACrC,WAAA,WAAW,cAAc,WAAW,OAAO,KAAK,CAAC,kBAAkB,SAAS,WAAW,YAAa,CAAA;AAAA,EAC5G;AAAA,EAEQ,qBAAqB,SAAmB;AAC/C,WAAO,QACL,IAAI,CAAM,OAAA,GAAG,aAAa,EAC1B,OAAO,KAAK,gBAAgB,EAC5B,KAAK,EACL,KAAK,GAAG;AAAA,EACX;AACD;"}
|