@hot-updater/aws 0.25.13 → 0.26.0
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/iac/index.cjs +298 -274
- package/dist/iac/index.js +298 -274
- package/dist/lambda/index.cjs +283 -295
- package/dist/lambda/index.d.cts +1 -0
- package/package.json +6 -6
package/dist/lambda/index.cjs
CHANGED
|
@@ -30,6 +30,8 @@ let path = require("path");
|
|
|
30
30
|
path = __toESM$1(path);
|
|
31
31
|
let node_crypto = require("node:crypto");
|
|
32
32
|
node_crypto = __toESM$1(node_crypto);
|
|
33
|
+
let __aws_sdk_client_s3 = require("@aws-sdk/client-s3");
|
|
34
|
+
__aws_sdk_client_s3 = __toESM$1(__aws_sdk_client_s3);
|
|
33
35
|
|
|
34
36
|
//#region ../../packages/core/dist/index.js
|
|
35
37
|
const HOT_UPDATE_DIR_NAME = ".hot-updater";
|
|
@@ -1424,253 +1426,33 @@ var isContentTypeBinary = (contentType) => {
|
|
|
1424
1426
|
};
|
|
1425
1427
|
|
|
1426
1428
|
//#endregion
|
|
1427
|
-
//#region
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
var __getOwnPropNames$1 = Object.getOwnPropertyNames;
|
|
1432
|
-
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
1433
|
-
var __name = (target, value) => __defProp$1(target, "name", {
|
|
1434
|
-
value,
|
|
1435
|
-
configurable: true
|
|
1436
|
-
});
|
|
1437
|
-
var __export = (target, all) => {
|
|
1438
|
-
for (var name in all) __defProp$1(target, name, {
|
|
1439
|
-
get: all[name],
|
|
1440
|
-
enumerable: true
|
|
1441
|
-
});
|
|
1442
|
-
};
|
|
1443
|
-
var __copyProps$1 = (to, from, except, desc) => {
|
|
1444
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
1445
|
-
for (let key of __getOwnPropNames$1(from)) if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$1(to, key, {
|
|
1446
|
-
get: () => from[key],
|
|
1447
|
-
enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
|
|
1448
|
-
});
|
|
1449
|
-
}
|
|
1450
|
-
return to;
|
|
1451
|
-
};
|
|
1452
|
-
var __toCommonJS = (mod) => __copyProps$1(__defProp$1({}, "__esModule", { value: true }), mod);
|
|
1453
|
-
var index_exports = {};
|
|
1454
|
-
__export(index_exports, {
|
|
1455
|
-
getSignedCookies: () => getSignedCookies,
|
|
1456
|
-
getSignedUrl: () => getSignedUrl$2
|
|
1457
|
-
});
|
|
1458
|
-
module.exports = __toCommonJS(index_exports);
|
|
1459
|
-
var import_crypto = require("crypto");
|
|
1460
|
-
function getSignedUrl$2({ dateLessThan, dateGreaterThan, url, keyPairId, privateKey, ipAddress, policy, passphrase }) {
|
|
1461
|
-
const cloudfrontSignBuilder = new CloudfrontSignBuilder({
|
|
1462
|
-
keyPairId,
|
|
1463
|
-
privateKey,
|
|
1464
|
-
passphrase
|
|
1465
|
-
});
|
|
1466
|
-
if (!url && !policy) throw new Error("@aws-sdk/cloudfront-signer: Please provide 'url' or 'policy'.");
|
|
1467
|
-
if (policy) cloudfrontSignBuilder.setCustomPolicy(policy);
|
|
1468
|
-
else cloudfrontSignBuilder.setPolicyParameters({
|
|
1469
|
-
url,
|
|
1470
|
-
dateLessThan,
|
|
1471
|
-
dateGreaterThan,
|
|
1472
|
-
ipAddress
|
|
1473
|
-
});
|
|
1474
|
-
let baseUrl;
|
|
1475
|
-
if (url) baseUrl = url;
|
|
1476
|
-
else if (policy) {
|
|
1477
|
-
const resources = getPolicyResources(policy);
|
|
1478
|
-
if (!resources[0]) throw new Error("@aws-sdk/cloudfront-signer: No URL provided and unable to determine URL from first policy statement resource.");
|
|
1479
|
-
baseUrl = resources[0].replace("*://", "https://");
|
|
1480
|
-
}
|
|
1481
|
-
const newURL = new URL(baseUrl);
|
|
1482
|
-
newURL.search = Array.from(newURL.searchParams.entries()).concat(Object.entries(cloudfrontSignBuilder.createCloudfrontAttribute())).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
1483
|
-
return getResource(newURL);
|
|
1484
|
-
}
|
|
1485
|
-
__name(getSignedUrl$2, "getSignedUrl");
|
|
1486
|
-
function getSignedCookies({ ipAddress, url, privateKey, keyPairId, dateLessThan, dateGreaterThan, policy, passphrase }) {
|
|
1487
|
-
const cloudfrontSignBuilder = new CloudfrontSignBuilder({
|
|
1488
|
-
keyPairId,
|
|
1489
|
-
privateKey,
|
|
1490
|
-
passphrase
|
|
1491
|
-
});
|
|
1492
|
-
if (policy) cloudfrontSignBuilder.setCustomPolicy(policy);
|
|
1493
|
-
else cloudfrontSignBuilder.setPolicyParameters({
|
|
1494
|
-
url,
|
|
1495
|
-
dateLessThan,
|
|
1496
|
-
dateGreaterThan,
|
|
1497
|
-
ipAddress
|
|
1498
|
-
});
|
|
1499
|
-
const cloudfrontCookieAttributes = cloudfrontSignBuilder.createCloudfrontAttribute();
|
|
1500
|
-
const cookies = {
|
|
1501
|
-
"CloudFront-Key-Pair-Id": cloudfrontCookieAttributes["Key-Pair-Id"],
|
|
1502
|
-
"CloudFront-Signature": cloudfrontCookieAttributes["Signature"]
|
|
1503
|
-
};
|
|
1504
|
-
if (cloudfrontCookieAttributes["Expires"]) cookies["CloudFront-Expires"] = cloudfrontCookieAttributes["Expires"];
|
|
1505
|
-
if (cloudfrontCookieAttributes["Policy"]) cookies["CloudFront-Policy"] = cloudfrontCookieAttributes["Policy"];
|
|
1506
|
-
return cookies;
|
|
1507
|
-
}
|
|
1508
|
-
__name(getSignedCookies, "getSignedCookies");
|
|
1509
|
-
function getPolicyResources(policy) {
|
|
1510
|
-
return ((typeof policy === "string" ? JSON.parse(policy) : policy)?.Statement ?? []).map((s) => s.Resource);
|
|
1511
|
-
}
|
|
1512
|
-
__name(getPolicyResources, "getPolicyResources");
|
|
1513
|
-
function getResource(url) {
|
|
1514
|
-
switch (url.protocol) {
|
|
1515
|
-
case "http:":
|
|
1516
|
-
case "https:":
|
|
1517
|
-
case "ws:":
|
|
1518
|
-
case "wss:": return url.toString();
|
|
1519
|
-
case "rtmp:": return url.pathname.replace(/^\//, "") + url.search + url.hash;
|
|
1520
|
-
default: throw new Error("Invalid URI scheme. Scheme must be one of http, https, or rtmp");
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
__name(getResource, "getResource");
|
|
1524
|
-
var CloudfrontSignBuilder = class {
|
|
1525
|
-
static {
|
|
1526
|
-
__name(this, "CloudfrontSignBuilder");
|
|
1527
|
-
}
|
|
1528
|
-
keyPairId;
|
|
1529
|
-
privateKey;
|
|
1530
|
-
passphrase;
|
|
1531
|
-
policy;
|
|
1532
|
-
customPolicy = false;
|
|
1533
|
-
dateLessThan;
|
|
1534
|
-
constructor({ privateKey, keyPairId, passphrase }) {
|
|
1535
|
-
this.keyPairId = keyPairId;
|
|
1536
|
-
this.privateKey = privateKey;
|
|
1537
|
-
this.policy = "";
|
|
1538
|
-
this.passphrase = passphrase;
|
|
1539
|
-
}
|
|
1540
|
-
buildPolicy(args) {
|
|
1541
|
-
const policy = { Statement: [{
|
|
1542
|
-
Resource: args.resource,
|
|
1543
|
-
Condition: { DateLessThan: { "AWS:EpochTime": args.dateLessThan } }
|
|
1544
|
-
}] };
|
|
1545
|
-
if (args.dateGreaterThan) policy.Statement[0].Condition["DateGreaterThan"] = { "AWS:EpochTime": args.dateGreaterThan };
|
|
1546
|
-
if (args.ipAddress) {
|
|
1547
|
-
const cidr = this.parseCIDR(args.ipAddress);
|
|
1548
|
-
policy.Statement[0].Condition["IpAddress"] = { "AWS:SourceIp": cidr };
|
|
1549
|
-
}
|
|
1550
|
-
return policy;
|
|
1551
|
-
}
|
|
1552
|
-
normalizeBase64(str) {
|
|
1553
|
-
const replacements = {
|
|
1554
|
-
"+": "-",
|
|
1555
|
-
"=": "_",
|
|
1556
|
-
"/": "~"
|
|
1557
|
-
};
|
|
1558
|
-
return str.replace(/[+=/]/g, function(match) {
|
|
1559
|
-
return replacements[match];
|
|
1560
|
-
});
|
|
1561
|
-
}
|
|
1562
|
-
encodeToBase64(str) {
|
|
1563
|
-
return this.normalizeBase64(Buffer.from(str).toString("base64"));
|
|
1564
|
-
}
|
|
1565
|
-
validateIP(ipStr) {
|
|
1566
|
-
const octets = ipStr.split(".");
|
|
1567
|
-
if (octets.length !== 4) throw new Error(`IP does not contain four octets.`);
|
|
1568
|
-
if (!octets.every((octet) => {
|
|
1569
|
-
const num = Number(octet);
|
|
1570
|
-
return Number.isInteger(num) && num >= 0 && num <= 255;
|
|
1571
|
-
})) throw new Error("invalid IP octets");
|
|
1572
|
-
}
|
|
1573
|
-
validateMask(maskStr) {
|
|
1574
|
-
const mask = Number(maskStr);
|
|
1575
|
-
if (!(Number.isInteger(mask) && mask >= 0 && mask <= 32)) throw new Error("invalid mask");
|
|
1576
|
-
}
|
|
1577
|
-
parseCIDR(cidrStr) {
|
|
1578
|
-
try {
|
|
1579
|
-
const cidrParts = cidrStr.split("/");
|
|
1580
|
-
if (cidrParts.some((part) => part.length === 0)) throw new Error("missing ip or mask part of CIDR");
|
|
1581
|
-
this.validateIP(cidrParts[0]);
|
|
1582
|
-
let mask = "32";
|
|
1583
|
-
if (cidrParts.length === 2) {
|
|
1584
|
-
this.validateMask(cidrParts[1]);
|
|
1585
|
-
mask = cidrParts[1];
|
|
1586
|
-
}
|
|
1587
|
-
return `${cidrParts[0]}/${mask}`;
|
|
1588
|
-
} catch (error) {
|
|
1589
|
-
const errMessage = `IP address "${cidrStr}" is invalid`;
|
|
1590
|
-
if (error instanceof Error) throw new Error(`${errMessage} due to ${error.message}.`);
|
|
1591
|
-
else throw new Error(`${errMessage}.`);
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
epochTime(date) {
|
|
1595
|
-
return Math.round(date.getTime() / 1e3);
|
|
1596
|
-
}
|
|
1597
|
-
parseDate(date) {
|
|
1598
|
-
if (!date) return;
|
|
1599
|
-
const parsedDate = new Date(date);
|
|
1600
|
-
return isNaN(parsedDate.getTime()) ? void 0 : this.epochTime(parsedDate);
|
|
1601
|
-
}
|
|
1602
|
-
parseDateWindow(expiration, start) {
|
|
1603
|
-
const dateLessThan = this.parseDate(expiration);
|
|
1604
|
-
if (!dateLessThan) throw new Error("dateLessThan is invalid. Ensure the date value is compatible with the Date constructor.");
|
|
1605
|
-
return {
|
|
1606
|
-
dateLessThan,
|
|
1607
|
-
dateGreaterThan: this.parseDate(start)
|
|
1608
|
-
};
|
|
1609
|
-
}
|
|
1610
|
-
signData(data, privateKey, passphrase) {
|
|
1611
|
-
const sign = (0, import_crypto.createSign)("RSA-SHA1");
|
|
1612
|
-
sign.update(data);
|
|
1613
|
-
return sign.sign({
|
|
1614
|
-
key: privateKey,
|
|
1615
|
-
passphrase
|
|
1616
|
-
}, "base64");
|
|
1617
|
-
}
|
|
1618
|
-
signPolicy(policy, privateKey, passphrase) {
|
|
1619
|
-
return this.normalizeBase64(this.signData(policy, privateKey, passphrase));
|
|
1620
|
-
}
|
|
1621
|
-
setCustomPolicy(policy) {
|
|
1622
|
-
this.customPolicy = true;
|
|
1623
|
-
this.policy = policy;
|
|
1624
|
-
}
|
|
1625
|
-
setPolicyParameters({ url, dateLessThan, dateGreaterThan, ipAddress }) {
|
|
1626
|
-
if (!url || !dateLessThan) return false;
|
|
1627
|
-
const resource = getResource(new URL(url));
|
|
1628
|
-
const parsedDates = this.parseDateWindow(dateLessThan, dateGreaterThan);
|
|
1629
|
-
this.dateLessThan = parsedDates.dateLessThan;
|
|
1630
|
-
this.customPolicy = Boolean(parsedDates.dateGreaterThan) || Boolean(ipAddress);
|
|
1631
|
-
this.policy = JSON.stringify(this.buildPolicy({
|
|
1632
|
-
resource,
|
|
1633
|
-
ipAddress,
|
|
1634
|
-
dateLessThan: parsedDates.dateLessThan,
|
|
1635
|
-
dateGreaterThan: parsedDates.dateGreaterThan
|
|
1636
|
-
}));
|
|
1637
|
-
}
|
|
1638
|
-
createCloudfrontAttribute() {
|
|
1639
|
-
if (!Boolean(this.policy)) throw new Error("Invalid policy");
|
|
1640
|
-
const signature = this.signPolicy(this.policy, this.privateKey, this.passphrase);
|
|
1641
|
-
return {
|
|
1642
|
-
Expires: this.customPolicy ? void 0 : this.dateLessThan,
|
|
1643
|
-
Policy: this.customPolicy ? this.encodeToBase64(this.policy) : void 0,
|
|
1644
|
-
"Key-Pair-Id": this.keyPairId,
|
|
1645
|
-
Signature: signature
|
|
1646
|
-
};
|
|
1647
|
-
}
|
|
1648
|
-
};
|
|
1649
|
-
}) });
|
|
1429
|
+
//#region lambda/cacheControl.ts
|
|
1430
|
+
const ONE_YEAR_IN_SECONDS = 3600 * 24 * 365;
|
|
1431
|
+
const NO_STORE_CACHE_CONTROL = "no-store";
|
|
1432
|
+
const SHARED_EDGE_CACHE_CONTROL = `public, max-age=0, s-maxage=${ONE_YEAR_IN_SECONDS}, must-revalidate`;
|
|
1650
1433
|
|
|
1651
1434
|
//#endregion
|
|
1652
1435
|
//#region ../js/dist/index.js
|
|
1653
|
-
var import_dist_cjs$1 = /* @__PURE__ */ __toESM$1(require_dist_cjs(), 1);
|
|
1654
1436
|
var __create = Object.create;
|
|
1655
|
-
var __defProp = Object.defineProperty;
|
|
1656
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
1657
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
1437
|
+
var __defProp$1 = Object.defineProperty;
|
|
1438
|
+
var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
|
|
1439
|
+
var __getOwnPropNames$1 = Object.getOwnPropertyNames;
|
|
1658
1440
|
var __getProtoOf = Object.getPrototypeOf;
|
|
1659
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
1441
|
+
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
|
|
1660
1442
|
var __commonJS = (cb, mod) => function() {
|
|
1661
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
1443
|
+
return mod || (0, cb[__getOwnPropNames$1(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
1662
1444
|
};
|
|
1663
|
-
var __copyProps = (to, from, except, desc) => {
|
|
1664
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
1445
|
+
var __copyProps$1 = (to, from, except, desc) => {
|
|
1446
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames$1(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
1665
1447
|
key = keys[i];
|
|
1666
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
1448
|
+
if (!__hasOwnProp$1.call(to, key) && key !== except) __defProp$1(to, key, {
|
|
1667
1449
|
get: ((k) => from[k]).bind(null, key),
|
|
1668
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
1450
|
+
enumerable: !(desc = __getOwnPropDesc$1(from, key)) || desc.enumerable
|
|
1669
1451
|
});
|
|
1670
1452
|
}
|
|
1671
1453
|
return to;
|
|
1672
1454
|
};
|
|
1673
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
1455
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps$1(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
|
|
1674
1456
|
value: mod,
|
|
1675
1457
|
enumerable: true
|
|
1676
1458
|
}) : target, mod));
|
|
@@ -3038,51 +2820,46 @@ const year = day * 365.25;
|
|
|
3038
2820
|
|
|
3039
2821
|
//#endregion
|
|
3040
2822
|
//#region lambda/getUpdateInfo.ts
|
|
3041
|
-
const
|
|
2823
|
+
const s3Clients = /* @__PURE__ */ new Map();
|
|
2824
|
+
const getS3Client = (region) => {
|
|
2825
|
+
const existingClient = s3Clients.get(region);
|
|
2826
|
+
if (existingClient) return existingClient;
|
|
2827
|
+
const client = new __aws_sdk_client_s3.S3({ region });
|
|
2828
|
+
s3Clients.set(region, client);
|
|
2829
|
+
return client;
|
|
2830
|
+
};
|
|
2831
|
+
const getS3Json = async ({ bucketName, key, region }) => {
|
|
3042
2832
|
try {
|
|
3043
|
-
const
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
2833
|
+
const body = await (await getS3Client(region).send(new __aws_sdk_client_s3.GetObjectCommand({
|
|
2834
|
+
Bucket: bucketName,
|
|
2835
|
+
Key: key
|
|
2836
|
+
}))).Body?.transformToString();
|
|
2837
|
+
if (!body) return null;
|
|
2838
|
+
return JSON.parse(body);
|
|
2839
|
+
} catch (error) {
|
|
2840
|
+
if (error instanceof Error && (error.name === "NoSuchKey" || error.name === "NotFound")) return null;
|
|
2841
|
+
console.error("Failed to read Hot Updater manifest from S3:", {
|
|
2842
|
+
key,
|
|
2843
|
+
error
|
|
3050
2844
|
});
|
|
3051
|
-
const res = await fetch(signedUrl, { headers: { "Content-Type": "application/json" } });
|
|
3052
|
-
if (!res.ok) return null;
|
|
3053
|
-
return res.json();
|
|
3054
|
-
} catch {
|
|
3055
2845
|
return null;
|
|
3056
2846
|
}
|
|
3057
2847
|
};
|
|
3058
|
-
const getUpdateInfo = async ({
|
|
2848
|
+
const getUpdateInfo = async ({ bucketName, region, readManifestJson }, args) => {
|
|
2849
|
+
const manifestReader = readManifestJson ?? ((key) => getS3Json({
|
|
2850
|
+
bucketName,
|
|
2851
|
+
key,
|
|
2852
|
+
region
|
|
2853
|
+
}));
|
|
3059
2854
|
switch (args._updateStrategy) {
|
|
3060
|
-
case "appVersion": return appVersionStrategy({
|
|
3061
|
-
|
|
3062
|
-
keyPairId,
|
|
3063
|
-
privateKey
|
|
3064
|
-
}, args);
|
|
3065
|
-
case "fingerprint": return fingerprintStrategy({
|
|
3066
|
-
baseUrl,
|
|
3067
|
-
keyPairId,
|
|
3068
|
-
privateKey
|
|
3069
|
-
}, args);
|
|
2855
|
+
case "appVersion": return appVersionStrategy({ readManifestJson: manifestReader }, args);
|
|
2856
|
+
case "fingerprint": return fingerprintStrategy({ readManifestJson: manifestReader }, args);
|
|
3070
2857
|
default: return null;
|
|
3071
2858
|
}
|
|
3072
2859
|
};
|
|
3073
|
-
const appVersionStrategy = async ({
|
|
3074
|
-
const matchingVersions = filterCompatibleAppVersions(await
|
|
3075
|
-
|
|
3076
|
-
key: `${channel}/${platform}/target-app-versions.json`,
|
|
3077
|
-
keyPairId,
|
|
3078
|
-
privateKey
|
|
3079
|
-
}) ?? [], appVersion);
|
|
3080
|
-
return getUpdateInfo$1((await Promise.allSettled(matchingVersions.map((targetAppVersion) => getCdnJson({
|
|
3081
|
-
baseUrl,
|
|
3082
|
-
key: `${channel}/${platform}/${targetAppVersion}/update.json`,
|
|
3083
|
-
keyPairId,
|
|
3084
|
-
privateKey
|
|
3085
|
-
})))).filter((r) => r.status === "fulfilled").flatMap((r) => r.value ?? []), {
|
|
2860
|
+
const appVersionStrategy = async ({ readManifestJson }, { platform, appVersion, bundleId, minBundleId = NIL_UUID, channel = "production" }) => {
|
|
2861
|
+
const matchingVersions = filterCompatibleAppVersions(await readManifestJson(`${channel}/${platform}/target-app-versions.json`) ?? [], appVersion);
|
|
2862
|
+
return getUpdateInfo$1((await Promise.allSettled(matchingVersions.map((targetAppVersion) => readManifestJson(`${channel}/${platform}/${targetAppVersion}/update.json`)))).filter((r) => r.status === "fulfilled").flatMap((r) => r.value ?? []), {
|
|
3086
2863
|
platform,
|
|
3087
2864
|
bundleId,
|
|
3088
2865
|
appVersion,
|
|
@@ -3091,15 +2868,8 @@ const appVersionStrategy = async ({ baseUrl, keyPairId, privateKey }, { platform
|
|
|
3091
2868
|
_updateStrategy: "appVersion"
|
|
3092
2869
|
});
|
|
3093
2870
|
};
|
|
3094
|
-
const fingerprintStrategy = async ({
|
|
3095
|
-
|
|
3096
|
-
baseUrl,
|
|
3097
|
-
key: `${channel}/${platform}/${fingerprintHash}/update.json`,
|
|
3098
|
-
keyPairId,
|
|
3099
|
-
privateKey
|
|
3100
|
-
});
|
|
3101
|
-
console.log("result", `${channel}/${platform}/${fingerprintHash}/update.json`, result);
|
|
3102
|
-
return getUpdateInfo$1(result ?? [], {
|
|
2871
|
+
const fingerprintStrategy = async ({ readManifestJson }, { platform, fingerprintHash, bundleId, minBundleId = NIL_UUID, channel = "production" }) => {
|
|
2872
|
+
return getUpdateInfo$1(await readManifestJson(`${channel}/${platform}/${fingerprintHash}/update.json`) ?? [], {
|
|
3103
2873
|
platform,
|
|
3104
2874
|
bundleId,
|
|
3105
2875
|
fingerprintHash,
|
|
@@ -3109,6 +2879,231 @@ const fingerprintStrategy = async ({ baseUrl, keyPairId, privateKey }, { platfor
|
|
|
3109
2879
|
});
|
|
3110
2880
|
};
|
|
3111
2881
|
|
|
2882
|
+
//#endregion
|
|
2883
|
+
//#region ../../node_modules/.pnpm/@aws-sdk+cloudfront-signer@3.772.0/node_modules/@aws-sdk/cloudfront-signer/dist-cjs/index.js
|
|
2884
|
+
var require_dist_cjs = /* @__PURE__ */ __commonJS$1({ "../../node_modules/.pnpm/@aws-sdk+cloudfront-signer@3.772.0/node_modules/@aws-sdk/cloudfront-signer/dist-cjs/index.js": ((exports, module) => {
|
|
2885
|
+
var __defProp = Object.defineProperty;
|
|
2886
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
2887
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2888
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
2889
|
+
var __name = (target, value) => __defProp(target, "name", {
|
|
2890
|
+
value,
|
|
2891
|
+
configurable: true
|
|
2892
|
+
});
|
|
2893
|
+
var __export = (target, all) => {
|
|
2894
|
+
for (var name in all) __defProp(target, name, {
|
|
2895
|
+
get: all[name],
|
|
2896
|
+
enumerable: true
|
|
2897
|
+
});
|
|
2898
|
+
};
|
|
2899
|
+
var __copyProps = (to, from, except, desc) => {
|
|
2900
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
2901
|
+
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
2902
|
+
get: () => from[key],
|
|
2903
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
2904
|
+
});
|
|
2905
|
+
}
|
|
2906
|
+
return to;
|
|
2907
|
+
};
|
|
2908
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
2909
|
+
var index_exports = {};
|
|
2910
|
+
__export(index_exports, {
|
|
2911
|
+
getSignedCookies: () => getSignedCookies,
|
|
2912
|
+
getSignedUrl: () => getSignedUrl$1
|
|
2913
|
+
});
|
|
2914
|
+
module.exports = __toCommonJS(index_exports);
|
|
2915
|
+
var import_crypto = require("crypto");
|
|
2916
|
+
function getSignedUrl$1({ dateLessThan, dateGreaterThan, url, keyPairId, privateKey, ipAddress, policy, passphrase }) {
|
|
2917
|
+
const cloudfrontSignBuilder = new CloudfrontSignBuilder({
|
|
2918
|
+
keyPairId,
|
|
2919
|
+
privateKey,
|
|
2920
|
+
passphrase
|
|
2921
|
+
});
|
|
2922
|
+
if (!url && !policy) throw new Error("@aws-sdk/cloudfront-signer: Please provide 'url' or 'policy'.");
|
|
2923
|
+
if (policy) cloudfrontSignBuilder.setCustomPolicy(policy);
|
|
2924
|
+
else cloudfrontSignBuilder.setPolicyParameters({
|
|
2925
|
+
url,
|
|
2926
|
+
dateLessThan,
|
|
2927
|
+
dateGreaterThan,
|
|
2928
|
+
ipAddress
|
|
2929
|
+
});
|
|
2930
|
+
let baseUrl;
|
|
2931
|
+
if (url) baseUrl = url;
|
|
2932
|
+
else if (policy) {
|
|
2933
|
+
const resources = getPolicyResources(policy);
|
|
2934
|
+
if (!resources[0]) throw new Error("@aws-sdk/cloudfront-signer: No URL provided and unable to determine URL from first policy statement resource.");
|
|
2935
|
+
baseUrl = resources[0].replace("*://", "https://");
|
|
2936
|
+
}
|
|
2937
|
+
const newURL = new URL(baseUrl);
|
|
2938
|
+
newURL.search = Array.from(newURL.searchParams.entries()).concat(Object.entries(cloudfrontSignBuilder.createCloudfrontAttribute())).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
2939
|
+
return getResource(newURL);
|
|
2940
|
+
}
|
|
2941
|
+
__name(getSignedUrl$1, "getSignedUrl");
|
|
2942
|
+
function getSignedCookies({ ipAddress, url, privateKey, keyPairId, dateLessThan, dateGreaterThan, policy, passphrase }) {
|
|
2943
|
+
const cloudfrontSignBuilder = new CloudfrontSignBuilder({
|
|
2944
|
+
keyPairId,
|
|
2945
|
+
privateKey,
|
|
2946
|
+
passphrase
|
|
2947
|
+
});
|
|
2948
|
+
if (policy) cloudfrontSignBuilder.setCustomPolicy(policy);
|
|
2949
|
+
else cloudfrontSignBuilder.setPolicyParameters({
|
|
2950
|
+
url,
|
|
2951
|
+
dateLessThan,
|
|
2952
|
+
dateGreaterThan,
|
|
2953
|
+
ipAddress
|
|
2954
|
+
});
|
|
2955
|
+
const cloudfrontCookieAttributes = cloudfrontSignBuilder.createCloudfrontAttribute();
|
|
2956
|
+
const cookies = {
|
|
2957
|
+
"CloudFront-Key-Pair-Id": cloudfrontCookieAttributes["Key-Pair-Id"],
|
|
2958
|
+
"CloudFront-Signature": cloudfrontCookieAttributes["Signature"]
|
|
2959
|
+
};
|
|
2960
|
+
if (cloudfrontCookieAttributes["Expires"]) cookies["CloudFront-Expires"] = cloudfrontCookieAttributes["Expires"];
|
|
2961
|
+
if (cloudfrontCookieAttributes["Policy"]) cookies["CloudFront-Policy"] = cloudfrontCookieAttributes["Policy"];
|
|
2962
|
+
return cookies;
|
|
2963
|
+
}
|
|
2964
|
+
__name(getSignedCookies, "getSignedCookies");
|
|
2965
|
+
function getPolicyResources(policy) {
|
|
2966
|
+
return ((typeof policy === "string" ? JSON.parse(policy) : policy)?.Statement ?? []).map((s) => s.Resource);
|
|
2967
|
+
}
|
|
2968
|
+
__name(getPolicyResources, "getPolicyResources");
|
|
2969
|
+
function getResource(url) {
|
|
2970
|
+
switch (url.protocol) {
|
|
2971
|
+
case "http:":
|
|
2972
|
+
case "https:":
|
|
2973
|
+
case "ws:":
|
|
2974
|
+
case "wss:": return url.toString();
|
|
2975
|
+
case "rtmp:": return url.pathname.replace(/^\//, "") + url.search + url.hash;
|
|
2976
|
+
default: throw new Error("Invalid URI scheme. Scheme must be one of http, https, or rtmp");
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
__name(getResource, "getResource");
|
|
2980
|
+
var CloudfrontSignBuilder = class {
|
|
2981
|
+
static {
|
|
2982
|
+
__name(this, "CloudfrontSignBuilder");
|
|
2983
|
+
}
|
|
2984
|
+
keyPairId;
|
|
2985
|
+
privateKey;
|
|
2986
|
+
passphrase;
|
|
2987
|
+
policy;
|
|
2988
|
+
customPolicy = false;
|
|
2989
|
+
dateLessThan;
|
|
2990
|
+
constructor({ privateKey, keyPairId, passphrase }) {
|
|
2991
|
+
this.keyPairId = keyPairId;
|
|
2992
|
+
this.privateKey = privateKey;
|
|
2993
|
+
this.policy = "";
|
|
2994
|
+
this.passphrase = passphrase;
|
|
2995
|
+
}
|
|
2996
|
+
buildPolicy(args) {
|
|
2997
|
+
const policy = { Statement: [{
|
|
2998
|
+
Resource: args.resource,
|
|
2999
|
+
Condition: { DateLessThan: { "AWS:EpochTime": args.dateLessThan } }
|
|
3000
|
+
}] };
|
|
3001
|
+
if (args.dateGreaterThan) policy.Statement[0].Condition["DateGreaterThan"] = { "AWS:EpochTime": args.dateGreaterThan };
|
|
3002
|
+
if (args.ipAddress) {
|
|
3003
|
+
const cidr = this.parseCIDR(args.ipAddress);
|
|
3004
|
+
policy.Statement[0].Condition["IpAddress"] = { "AWS:SourceIp": cidr };
|
|
3005
|
+
}
|
|
3006
|
+
return policy;
|
|
3007
|
+
}
|
|
3008
|
+
normalizeBase64(str) {
|
|
3009
|
+
const replacements = {
|
|
3010
|
+
"+": "-",
|
|
3011
|
+
"=": "_",
|
|
3012
|
+
"/": "~"
|
|
3013
|
+
};
|
|
3014
|
+
return str.replace(/[+=/]/g, function(match) {
|
|
3015
|
+
return replacements[match];
|
|
3016
|
+
});
|
|
3017
|
+
}
|
|
3018
|
+
encodeToBase64(str) {
|
|
3019
|
+
return this.normalizeBase64(Buffer.from(str).toString("base64"));
|
|
3020
|
+
}
|
|
3021
|
+
validateIP(ipStr) {
|
|
3022
|
+
const octets = ipStr.split(".");
|
|
3023
|
+
if (octets.length !== 4) throw new Error(`IP does not contain four octets.`);
|
|
3024
|
+
if (!octets.every((octet) => {
|
|
3025
|
+
const num = Number(octet);
|
|
3026
|
+
return Number.isInteger(num) && num >= 0 && num <= 255;
|
|
3027
|
+
})) throw new Error("invalid IP octets");
|
|
3028
|
+
}
|
|
3029
|
+
validateMask(maskStr) {
|
|
3030
|
+
const mask = Number(maskStr);
|
|
3031
|
+
if (!(Number.isInteger(mask) && mask >= 0 && mask <= 32)) throw new Error("invalid mask");
|
|
3032
|
+
}
|
|
3033
|
+
parseCIDR(cidrStr) {
|
|
3034
|
+
try {
|
|
3035
|
+
const cidrParts = cidrStr.split("/");
|
|
3036
|
+
if (cidrParts.some((part) => part.length === 0)) throw new Error("missing ip or mask part of CIDR");
|
|
3037
|
+
this.validateIP(cidrParts[0]);
|
|
3038
|
+
let mask = "32";
|
|
3039
|
+
if (cidrParts.length === 2) {
|
|
3040
|
+
this.validateMask(cidrParts[1]);
|
|
3041
|
+
mask = cidrParts[1];
|
|
3042
|
+
}
|
|
3043
|
+
return `${cidrParts[0]}/${mask}`;
|
|
3044
|
+
} catch (error) {
|
|
3045
|
+
const errMessage = `IP address "${cidrStr}" is invalid`;
|
|
3046
|
+
if (error instanceof Error) throw new Error(`${errMessage} due to ${error.message}.`);
|
|
3047
|
+
else throw new Error(`${errMessage}.`);
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
epochTime(date) {
|
|
3051
|
+
return Math.round(date.getTime() / 1e3);
|
|
3052
|
+
}
|
|
3053
|
+
parseDate(date) {
|
|
3054
|
+
if (!date) return;
|
|
3055
|
+
const parsedDate = new Date(date);
|
|
3056
|
+
return isNaN(parsedDate.getTime()) ? void 0 : this.epochTime(parsedDate);
|
|
3057
|
+
}
|
|
3058
|
+
parseDateWindow(expiration, start) {
|
|
3059
|
+
const dateLessThan = this.parseDate(expiration);
|
|
3060
|
+
if (!dateLessThan) throw new Error("dateLessThan is invalid. Ensure the date value is compatible with the Date constructor.");
|
|
3061
|
+
return {
|
|
3062
|
+
dateLessThan,
|
|
3063
|
+
dateGreaterThan: this.parseDate(start)
|
|
3064
|
+
};
|
|
3065
|
+
}
|
|
3066
|
+
signData(data, privateKey, passphrase) {
|
|
3067
|
+
const sign = (0, import_crypto.createSign)("RSA-SHA1");
|
|
3068
|
+
sign.update(data);
|
|
3069
|
+
return sign.sign({
|
|
3070
|
+
key: privateKey,
|
|
3071
|
+
passphrase
|
|
3072
|
+
}, "base64");
|
|
3073
|
+
}
|
|
3074
|
+
signPolicy(policy, privateKey, passphrase) {
|
|
3075
|
+
return this.normalizeBase64(this.signData(policy, privateKey, passphrase));
|
|
3076
|
+
}
|
|
3077
|
+
setCustomPolicy(policy) {
|
|
3078
|
+
this.customPolicy = true;
|
|
3079
|
+
this.policy = policy;
|
|
3080
|
+
}
|
|
3081
|
+
setPolicyParameters({ url, dateLessThan, dateGreaterThan, ipAddress }) {
|
|
3082
|
+
if (!url || !dateLessThan) return false;
|
|
3083
|
+
const resource = getResource(new URL(url));
|
|
3084
|
+
const parsedDates = this.parseDateWindow(dateLessThan, dateGreaterThan);
|
|
3085
|
+
this.dateLessThan = parsedDates.dateLessThan;
|
|
3086
|
+
this.customPolicy = Boolean(parsedDates.dateGreaterThan) || Boolean(ipAddress);
|
|
3087
|
+
this.policy = JSON.stringify(this.buildPolicy({
|
|
3088
|
+
resource,
|
|
3089
|
+
ipAddress,
|
|
3090
|
+
dateLessThan: parsedDates.dateLessThan,
|
|
3091
|
+
dateGreaterThan: parsedDates.dateGreaterThan
|
|
3092
|
+
}));
|
|
3093
|
+
}
|
|
3094
|
+
createCloudfrontAttribute() {
|
|
3095
|
+
if (!Boolean(this.policy)) throw new Error("Invalid policy");
|
|
3096
|
+
const signature = this.signPolicy(this.policy, this.privateKey, this.passphrase);
|
|
3097
|
+
return {
|
|
3098
|
+
Expires: this.customPolicy ? void 0 : this.dateLessThan,
|
|
3099
|
+
Policy: this.customPolicy ? this.encodeToBase64(this.policy) : void 0,
|
|
3100
|
+
"Key-Pair-Id": this.keyPairId,
|
|
3101
|
+
Signature: signature
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
};
|
|
3105
|
+
}) });
|
|
3106
|
+
|
|
3112
3107
|
//#endregion
|
|
3113
3108
|
//#region lambda/withSignedUrl.ts
|
|
3114
3109
|
var import_dist_cjs = /* @__PURE__ */ __toESM$1(require_dist_cjs(), 1);
|
|
@@ -3149,11 +3144,8 @@ const withSignedUrl = async ({ data, reqUrl, keyPairId, privateKey, expiresSecon
|
|
|
3149
3144
|
const CLOUDFRONT_KEY_PAIR_ID = HotUpdater.CLOUDFRONT_KEY_PAIR_ID;
|
|
3150
3145
|
const SSM_PARAMETER_NAME = HotUpdater.SSM_PARAMETER_NAME;
|
|
3151
3146
|
const SSM_REGION = HotUpdater.SSM_REGION;
|
|
3147
|
+
const S3_BUCKET_NAME = HotUpdater.S3_BUCKET_NAME;
|
|
3152
3148
|
let cachedPrivateKey = null;
|
|
3153
|
-
/**
|
|
3154
|
-
* Retrieves CloudFront private key from SSM Parameter Store
|
|
3155
|
-
* Uses global cache to avoid repeated SSM calls on warm Lambda invocations
|
|
3156
|
-
*/
|
|
3157
3149
|
async function getPrivateKey() {
|
|
3158
3150
|
if (cachedPrivateKey !== null) return cachedPrivateKey;
|
|
3159
3151
|
if (!SSM_REGION) throw new Error(`Invalid AWS region format: ${SSM_REGION}. Expected format like 'us-east-1' or 'ap-southeast-1'`);
|
|
@@ -3186,10 +3178,8 @@ const processDefaultValues = (channel, minBundleId) => ({
|
|
|
3186
3178
|
actualChannel: channel === "default" ? "production" : channel,
|
|
3187
3179
|
actualMinBundleId: minBundleId === "default" ? NIL_UUID : minBundleId
|
|
3188
3180
|
});
|
|
3189
|
-
const handleUpdateRequest = async (c, params, strategy, expiresSeconds) => {
|
|
3181
|
+
const handleUpdateRequest = async (c, params, strategy, expiresSeconds, cacheControl) => {
|
|
3190
3182
|
try {
|
|
3191
|
-
if (!c.req.header("host")) return c.json({ error: "Missing host header." }, 500);
|
|
3192
|
-
const privateKey = await getPrivateKey();
|
|
3193
3183
|
const updateConfig = {
|
|
3194
3184
|
platform: params.platform,
|
|
3195
3185
|
bundleId: params.bundleId,
|
|
@@ -3204,11 +3194,12 @@ const handleUpdateRequest = async (c, params, strategy, expiresSeconds) => {
|
|
|
3204
3194
|
}
|
|
3205
3195
|
};
|
|
3206
3196
|
const updateInfo = await getUpdateInfo({
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
privateKey
|
|
3197
|
+
bucketName: S3_BUCKET_NAME,
|
|
3198
|
+
region: SSM_REGION
|
|
3210
3199
|
}, updateConfig);
|
|
3200
|
+
if (cacheControl) c.header("Cache-Control", cacheControl);
|
|
3211
3201
|
if (!updateInfo) return c.json(null);
|
|
3202
|
+
const privateKey = await getPrivateKey();
|
|
3212
3203
|
const appUpdateInfo = await withSignedUrl({
|
|
3213
3204
|
data: updateInfo,
|
|
3214
3205
|
reqUrl: c.req.url,
|
|
@@ -3244,7 +3235,7 @@ app.get("/api/check-update", async (c) => {
|
|
|
3244
3235
|
channel,
|
|
3245
3236
|
minBundleId,
|
|
3246
3237
|
...fingerprintHash ? { fingerprintHash } : { appVersion }
|
|
3247
|
-
}, fingerprintHash ? "fingerprint" : "appVersion", 60);
|
|
3238
|
+
}, fingerprintHash ? "fingerprint" : "appVersion", 60, NO_STORE_CACHE_CONTROL);
|
|
3248
3239
|
} catch (error) {
|
|
3249
3240
|
console.error("Legacy endpoint error:", error);
|
|
3250
3241
|
return c.json({ error: "Internal Server Error" }, 500);
|
|
@@ -3270,7 +3261,7 @@ app.get("/api/check-update/app-version/:platform/:appVersion/:channel/:minBundle
|
|
|
3270
3261
|
channel: actualChannel,
|
|
3271
3262
|
minBundleId: actualMinBundleId,
|
|
3272
3263
|
appVersion
|
|
3273
|
-
}, "appVersion",
|
|
3264
|
+
}, "appVersion", ONE_YEAR_IN_SECONDS, SHARED_EDGE_CACHE_CONTROL);
|
|
3274
3265
|
});
|
|
3275
3266
|
app.get("/api/check-update/fingerprint/:platform/:fingerprintHash/:channel/:minBundleId/:bundleId", async (c) => {
|
|
3276
3267
|
const { platform, fingerprintHash, channel, minBundleId, bundleId } = c.req.param();
|
|
@@ -3292,10 +3283,7 @@ app.get("/api/check-update/fingerprint/:platform/:fingerprintHash/:channel/:minB
|
|
|
3292
3283
|
channel: actualChannel,
|
|
3293
3284
|
minBundleId: actualMinBundleId,
|
|
3294
3285
|
fingerprintHash
|
|
3295
|
-
}, "fingerprint",
|
|
3296
|
-
});
|
|
3297
|
-
app.get("*", async (c) => {
|
|
3298
|
-
return c.env.callback(null, c.env.request);
|
|
3286
|
+
}, "fingerprint", ONE_YEAR_IN_SECONDS, SHARED_EDGE_CACHE_CONTROL);
|
|
3299
3287
|
});
|
|
3300
3288
|
const handler = handle(app);
|
|
3301
3289
|
|