diff --git a/package-lock.json b/package-lock.json index 4ef2863..a6945c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "0.0.13", "dependencies": { "@devicefarmer/adbkit-apkreader": "^3.2.4", - "aab-parser": "^1.0.1", "adm-zip": "^0.5.16", "backslash": "^0.2.0", "bplist-parser": "^0.3.2", @@ -19,6 +18,7 @@ "email-validator": "^2.0.4", "gradle-to-js": "2.0.1", "jsonwebtoken": "^9.0.2", + "jszip": "^3.10.1", "moment": "^2.29.4", "opener": "^1.5.2", "parse-duration": "1.1.0", @@ -26,6 +26,7 @@ "progress": "^2.0.3", "prompt": "^1.3.0", "properties": "^1.2.1", + "protobufjs": "^7.6.3", "q": "~1.5.1", "recursive-fs": "2.1.0", "rimraf": "^2.5.1", @@ -616,8 +617,7 @@ "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", @@ -626,25 +626,21 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==" }, "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==" }, "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "@protobufjs/aspromise": "^1.1.1" } }, "node_modules/@protobufjs/float": { @@ -653,12 +649,6 @@ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "license": "BSD-3-Clause" }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", @@ -844,12 +834,6 @@ "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, - "node_modules/@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", - "license": "MIT" - }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -1252,16 +1236,6 @@ "node": ">=10.0.0" } }, - "node_modules/aab-parser": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/aab-parser/-/aab-parser-1.0.1.tgz", - "integrity": "sha512-X8+gHK60IpKyCY454QLKW4fQ9u8rWPYNrE5j5FeDeruecBZxXmlgPNZEHE2Wg9hmXWiP+1HRIBwUQ/cflsSmUg==", - "license": "MIT", - "dependencies": { - "jszip": "^3.7.1", - "protobufjs": "^6.11.2" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -3377,10 +3351,9 @@ } }, "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "license": "Apache-2.0" + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" }, "node_modules/lru-cache": { "version": "10.4.3", @@ -4063,28 +4036,25 @@ } }, "node_modules/protobufjs": { - "version": "6.11.6", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.6.tgz", - "integrity": "sha512-k8BHqgPBOtrlougZZqF2uUk5Z7bN8f0wj+3e8M3hvtSv0NBAz4VBy5f6R5Nxq/l+i7mRFTgNZb2trxqTpHNY/A==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.5.tgz", + "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", + "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", - "long": "^4.0.0" + "long": "^5.3.2" }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" + "engines": { + "node": ">=12.0.0" } }, "node_modules/proxy-addr": { diff --git a/package.json b/package.json index 9b0aaa5..417d7ff 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ ], "dependencies": { "@devicefarmer/adbkit-apkreader": "^3.2.4", - "aab-parser": "^1.0.1", "adm-zip": "^0.5.16", "backslash": "^0.2.0", "bplist-parser": "^0.3.2", @@ -34,6 +33,7 @@ "email-validator": "^2.0.4", "gradle-to-js": "2.0.1", "jsonwebtoken": "^9.0.2", + "jszip": "^3.10.1", "moment": "^2.29.4", "opener": "^1.5.2", "parse-duration": "1.1.0", @@ -41,6 +41,7 @@ "progress": "^2.0.3", "prompt": "^1.3.0", "properties": "^1.2.1", + "protobufjs": "^7.6.3", "q": "~1.5.1", "recursive-fs": "2.1.0", "rimraf": "^2.5.1", diff --git a/script/command-executor.ts b/script/command-executor.ts index 0488e2d..4d43a52 100644 --- a/script/command-executor.ts +++ b/script/command-executor.ts @@ -15,7 +15,7 @@ import * as semver from "semver"; import * as cli from "../script/types/cli"; import sign from "./sign"; const ApkReader = require("@devicefarmer/adbkit-apkreader"); -const aabParser = require("aab-parser"); +import { parseAabManifest } from "./utils/aab-utils"; import { AccessKey, Account, @@ -1564,7 +1564,7 @@ export const releaseNative = (command: cli.IReleaseNativeCommand): Promise } else if (targetBinaryPathNormalised.endsWith(".aab")) { log(chalk.cyan(`\nExtracting AAB file:\n`)); await extractAAB(targetBinaryPath, extractFolder); - const { versionName: appStoreVersion, versionCode } = await aabParser.parseAabManifest(targetBinaryPath); + const { versionName: appStoreVersion, versionCode } = await parseAabManifest(targetBinaryPath); const metadataZip = await extractMetadataFromAndroid(`${extractFolder}/base`, outputFolder); // base folder is nested in AAB releaseCommandPartial = { diff --git a/script/utils/aab-utils.ts b/script/utils/aab-utils.ts new file mode 100644 index 0000000..2fe4203 --- /dev/null +++ b/script/utils/aab-utils.ts @@ -0,0 +1,59 @@ +// Minimal Android App Bundle (.aab) manifest reader; replaces the unmaintained +// aab-parser, which pinned a vulnerable protobufjs (^6.11.2). + +import * as fs from "fs"; +import * as jszip from "jszip"; +import * as protobuf from "protobufjs"; + +export type AabManifest = { + versionCode: number; + versionName: string; + packageName: string; + compiledSdkVersion: number; + compiledSdkVersionCodename: number; +}; + +type ManifestAttribute = { name: string; value: string }; + +// An AAB's is protobuf-encoded as an aapt.pb.XmlNode. We only read a +// few attributes, so we declare just that slice (field numbers from AOSP +// aapt2/Resources.proto); the decoder skips every field we omit. +const XmlNode = protobuf.parse(` + syntax = "proto3"; + package aapt.pb; + message XmlAttribute { string name = 2; string value = 3; } + message XmlElement { string name = 3; repeated XmlAttribute attribute = 4; } + message XmlNode { XmlElement element = 1; } +`).root.lookupType("aapt.pb.XmlNode"); + +async function readManifestAttributes(file: string | Buffer): Promise { + const buffer = typeof file === "string" ? await fs.promises.readFile(file) : file; + const archive = await jszip.loadAsync(buffer); + const manifest = await archive.file("base/manifest/AndroidManifest.xml")?.async("nodebuffer"); + if (manifest === undefined) { + throw new Error("Could not find AndroidManifest.xml file inside the app bundle file"); + } + + const decoded = XmlNode.decode(manifest).toJSON() as { element?: { attribute?: ManifestAttribute[] } }; + return decoded.element?.attribute ?? []; +} + +export async function parseAabManifest(file: string | Buffer): Promise { + const attributes = await readManifestAttributes(file); + + function getAttribute(name: string): string { + const attribute = attributes.find((attr) => attr.name === name); + if (attribute === undefined) { + throw new Error(`Attribute "${name}" not found in AndroidManifest.xml`); + } + return attribute.value; + } + + return { + versionCode: Number(getAttribute("versionCode")), + versionName: getAttribute("versionName"), + packageName: getAttribute("package"), + compiledSdkVersion: Number(getAttribute("compileSdkVersion")), + compiledSdkVersionCodename: Number(getAttribute("compileSdkVersionCodename")), + }; +}