New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

apk-mitm

Package Overview
Dependencies
Maintainers
1
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

apk-mitm - npm Package Compare versions

Comparing version 0.9.4 to 0.9.5

dist/utils/observe-async.js

30

dist/cli.js

@@ -83,11 +83,3 @@ "use strict";

}).catch((error) => {
const message = (error.all || (error.toString().replace(/^Error: /, '')))
// Replace mentions of the (sometimes very long) temporary directory path
.replace(new RegExp(tmpDir, 'g'), chalk_1.default `{bold <tmp_dir>}`)
// Highlight (usually relevant) warning lines in Apktool output
.replace(/^W: .+$/gm, line => chalk_1.default `{yellow ${line}}`)
// De-emphasize Apktool info lines
.replace(/^I: .+$/gm, line => chalk_1.default `{dim ${line}}`)
// De-emphasize (not very helpful) Apktool "could not exec" error message
.replace(/^.+brut\.common\.BrutException: could not exec.+$/gm, line => chalk_1.default `{dim ${line}}`);
const message = getErrorMessage(error, { tmpDir });
console.error([

@@ -99,4 +91,4 @@ '',

'',
` The full logs of all commands are available here:`,
` ${path_1.default.join(tmpDir, 'logs')}`,
` The full logs of all commands are available here:`,
` ${path_1.default.join(tmpDir, 'logs')}`,
''

@@ -109,2 +101,18 @@ ].join('\n'));

}
function getErrorMessage(error, { tmpDir }) {
if (error.all)
return formatCommandError(error.all, { tmpDir });
return error.stack;
}
function formatCommandError(error, { tmpDir }) {
return error
// Replace mentions of the (sometimes very long) temporary directory path
.replace(new RegExp(tmpDir, 'g'), chalk_1.default `{bold <tmp_dir>}`)
// Highlight (usually relevant) warning lines in Apktool output
.replace(/^W: .+$/gm, line => chalk_1.default `{yellow ${line}}`)
// De-emphasize Apktool info lines
.replace(/^I: .+$/gm, line => chalk_1.default `{dim ${line}}`)
// De-emphasize (not very helpful) Apktool "could not exec" error message
.replace(/^.+brut\.common\.BrutException: could not exec.+$/gm, line => chalk_1.default `{dim ${line}}`);
}
function showHelp() {

@@ -111,0 +119,0 @@ console.log(chalk_1.default `

@@ -27,4 +27,4 @@ "use strict";

const path = __importStar(require("path"));
const events_1 = require("events");
const fs = __importStar(require("./utils/fs"));
const rxjs_1 = require("rxjs");
const listr_1 = __importDefault(require("listr"));

@@ -36,2 +36,3 @@ const chalk_1 = __importDefault(require("chalk"));

const disable_certificate_pinning_1 = __importDefault(require("./tasks/disable-certificate-pinning"));
const observe_async_1 = __importDefault(require("./utils/observe-async"));
function patchApk(taskOptions) {

@@ -69,14 +70,10 @@ const { inputPath, outputPath, tmpDir, apktool, uberApkSigner, wait, } = taskOptions;

enabled: () => wait,
task: (_) => {
return new rxjs_1.Observable(subscriber => {
process.stdin.setEncoding('utf-8');
process.stdin.setRawMode(true);
subscriber.next("Press any key to continue.");
process.stdin.once('data', () => {
subscriber.complete();
process.stdin.setRawMode(false);
process.stdin.pause();
});
});
},
task: () => observe_async_1.default(async (next) => {
process.stdin.setEncoding('utf-8');
process.stdin.setRawMode(true);
next('Press any key to continue.');
await events_1.once(process.stdin, 'data');
process.stdin.setRawMode(false);
process.stdin.pause();
})
},

@@ -88,8 +85,10 @@ {

title: 'Encoding using AAPT2',
task: (_, task) => new rxjs_1.Observable(subscriber => {
apktool.encode(decodeDir, tmpApkPath, true).subscribe(line => subscriber.next(line), () => {
subscriber.complete();
task: (_, task) => observe_async_1.default(async (next) => {
try {
await apktool.encode(decodeDir, tmpApkPath, true).forEach(next);
}
catch (_a) {
task.skip('Failed, falling back to AAPT...');
fallBackToAapt = true;
}, () => subscriber.complete());
}
}),

@@ -106,11 +105,7 @@ },

title: 'Signing patched APK file',
task: () => new rxjs_1.Observable(subscriber => {
(async () => {
await uberApkSigner
.sign([tmpApkPath], { zipalign: true })
.forEach(line => subscriber.next(line))
.catch(error => subscriber.error(error));
await fs.copyFile(tmpApkPath, outputPath);
subscriber.complete();
})();
task: () => observe_async_1.default(async (next) => {
await uberApkSigner
.sign([tmpApkPath], { zipalign: true })
.forEach(line => next(line));
await fs.copyFile(tmpApkPath, outputPath);
}),

@@ -117,0 +112,0 @@ },

@@ -27,3 +27,2 @@ "use strict";

const cross_zip_1 = require("@tybys/cross-zip");
const rxjs_1 = require("rxjs");
const fs = __importStar(require("./utils/fs"));

@@ -34,2 +33,3 @@ const path = __importStar(require("path"));

const patch_apk_1 = __importDefault(require("./patch-apk"));
const observe_async_1 = __importDefault(require("./utils/observe-async"));
function patchXapkBundle(options) {

@@ -69,10 +69,7 @@ return patchAppBundle(options, { isXapk: true });

title: 'Signing APKs',
task: () => new rxjs_1.Observable(subscriber => {
(async () => {
const apkFiles = await globby_1.default(path.join(bundleDir, '**/*.apk'));
await uberApkSigner
.sign(apkFiles, { zipalign: false })
.forEach(line => subscriber.next(line));
subscriber.complete();
})();
task: () => observe_async_1.default(async (next) => {
const apkFiles = await globby_1.default(path.join(bundleDir, '**/*.apk'));
await uberApkSigner
.sign(apkFiles, { zipalign: false })
.forEach(line => next(line));
}),

@@ -79,0 +76,0 @@ },

@@ -30,3 +30,3 @@ "use strict";

const escape_string_regexp_1 = __importDefault(require("escape-string-regexp"));
const rxjs_1 = require("rxjs");
const observe_async_1 = __importDefault(require("../utils/observe-async"));
const INTERFACE_LINE = '.implements Ljavax/net/ssl/X509TrustManager;';

@@ -57,59 +57,57 @@ /** The methods that need to be patched to disable certificate pinning. */

async function disableCertificatePinning(directoryPath, task) {
return new rxjs_1.Observable(observer => {
(async () => {
observer.next('Finding smali files...');
// Convert Windows path (using backslashes) to POSIX path (using slashes)
const directoryPathPosix = directoryPath.split(path.sep).join(path.posix.sep);
const globPattern = path.posix.join(directoryPathPosix, 'smali*/**/*.smali');
const smaliFiles = await globby_1.default(globPattern);
let pinningFound = false;
for (const filePath of smaliFiles) {
observer.next(`Scanning ${path.basename(filePath)}...`);
let originalContent = await fs.readFile(filePath, 'utf-8');
// Don't scan classes that don't implement the interface
if (!originalContent.includes(INTERFACE_LINE))
continue;
return observe_async_1.default(async (next) => {
next('Finding smali files...');
// Convert Windows path (using backslashes) to POSIX path (using slashes)
const directoryPathPosix = directoryPath.split(path.sep).join(path.posix.sep);
const globPattern = path.posix.join(directoryPathPosix, 'smali*/**/*.smali');
let pinningFound = false;
for await (const filePathChunk of globby_1.default.stream(globPattern)) {
// Required because Node.js streams are not typed as generics
const filePath = filePathChunk;
next(`Scanning ${path.basename(filePath)}...`);
let originalContent = await fs.readFile(filePath, 'utf-8');
// Don't scan classes that don't implement the interface
if (!originalContent.includes(INTERFACE_LINE))
continue;
if (os.type() === 'Windows_NT') {
// Replace CRLF with LF, so that patches can just use '\n'
originalContent = originalContent.replace(/\r\n/g, '\n');
}
let patchedContent = originalContent;
for (const pattern of METHOD_PATTERNS) {
patchedContent = patchedContent.replace(pattern, (_, openingLine, body, closingLine) => {
const bodyLines = body
.split('\n')
.map(line => line.replace(/^ /, ''));
const fixLines = openingLine.includes('getAcceptedIssuers')
? RETURN_EMPTY_ARRAY_FIX
: RETURN_VOID_FIX;
const patchedBodyLines = [
'# inserted by apk-mitm to disable certificate pinning',
...fixLines,
'',
'# commented out by apk-mitm to disable old method body',
'# ',
...bodyLines.map(line => `# ${line}`)
];
return [
openingLine,
...patchedBodyLines.map(line => ` ${line}`),
closingLine,
].map(line => line.trimEnd()).join('\n');
});
}
if (originalContent !== patchedContent) {
pinningFound = true;
if (os.type() === 'Windows_NT') {
// Replace CRLF with LF, so that patches can just use '\n'
originalContent = originalContent.replace(/\r\n/g, '\n');
// Replace LF with CRLF again
patchedContent = patchedContent.replace(/\n/g, '\r\n');
}
let patchedContent = originalContent;
for (const pattern of METHOD_PATTERNS) {
patchedContent = patchedContent.replace(pattern, (_, openingLine, body, closingLine) => {
const bodyLines = body
.split('\n')
.map(line => line.replace(/^ /, ''));
const fixLines = openingLine.includes('getAcceptedIssuers')
? RETURN_EMPTY_ARRAY_FIX
: RETURN_VOID_FIX;
const patchedBodyLines = [
'# inserted by apk-mitm to disable certificate pinning',
...fixLines,
'',
'# commented out by apk-mitm to disable old method body',
'# ',
...bodyLines.map(line => `# ${line}`)
];
return [
openingLine,
...patchedBodyLines.map(line => ` ${line}`),
closingLine,
].map(line => line.trimEnd()).join('\n');
});
}
if (originalContent !== patchedContent) {
pinningFound = true;
if (os.type() === 'Windows_NT') {
// Replace LF with CRLF again
patchedContent = patchedContent.replace(/\n/g, '\r\n');
}
await fs.writeFile(filePath, patchedContent);
}
await fs.writeFile(filePathChunk, patchedContent);
}
if (!pinningFound)
task.skip('No certificate pinning logic found.');
observer.complete();
})();
}
if (!pinningFound)
task.skip('No certificate pinning logic found.');
});
}
exports.default = disableCertificatePinning;

@@ -1,81 +0,55 @@

'use strict'
var __importStar =
(this && this.__importStar) ||
function (mod) {
if (mod && mod.__esModule) return mod
var result = {}
if (mod != null)
for (var k in mod)
if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]
result['default'] = mod
return result
}
Object.defineProperty(exports, '__esModule', { value: true })
const fs = __importStar(require('fs'))
const fs_1 = require('fs')
const pathUtils = __importStar(require('path'))
const envPaths = require('env-paths')
const rxjs_1 = require('rxjs')
const followRedirects = require('follow-redirects')
const { https } = followRedirects
const cachePath = envPaths('apk-mitm', { suffix: '' }).cache
function createToolDownloadTask(tool) {
return {
title: `Downloading ${tool.name} ${tool.version.name}`,
task: (_, task) => {
if (!tool.version.downloadUrl) return task.skip('Using custom version')
const fileName = `${tool.name}-${tool.version.name}.jar`
return downloadFile(task, tool.version.downloadUrl, fileName)
},
}
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("./fs"));
const rxjs_1 = require("rxjs");
const followRedirects = require("follow-redirects");
const { https } = followRedirects;
function downloadFile(url, path) {
return new rxjs_1.Observable(subscriber => {
https.get(url, response => {
if (response.statusCode !== 200) {
const error = new Error(`The URL "${url}" returned status code ${response.statusCode}, expected 200.`);
// Cancel download with error
response.destroy(error);
}
const fileStream = fs.createWriteStream(path);
const totalLength = parseInt(response.headers['content-length']);
let currentLength = 0;
const reportProgress = () => {
const percentage = currentLength / totalLength;
subscriber.next(`${(percentage * 100).toFixed(2)}% done (${formatBytes(currentLength)} / ${formatBytes(totalLength)} MB)`);
};
reportProgress();
response.pipe(fileStream);
response.on('data', (chunk) => {
currentLength += chunk.byteLength;
reportProgress();
});
response.on('error', error => subscriber.error(error));
fileStream.on('close', () => subscriber.complete());
}).on('error', error => subscriber.error(error));
});
}
exports.createToolDownloadTask = createToolDownloadTask
function downloadFile(task, url, fileName) {
return new rxjs_1.Observable(subscriber => {
;(async () => {
const finalFilePath = getCachedPath(fileName)
if (fs.existsSync(finalFilePath)) {
task.skip('Version already downloaded!')
subscriber.complete()
return
}
// Ensure cache directory exists
await fs_1.promises.mkdir(cachePath, { recursive: true })
// Prevent file corruption by using a temporary file name
const downloadFilePath = finalFilePath + '.dl'
https
.get(url, response => {
const fileStream = fs.createWriteStream(downloadFilePath)
const totalLength = parseInt(response.headers['content-length'])
let currentLength = 0
const reportProgress = () => {
const percentage = currentLength / totalLength
subscriber.next(
`${(percentage * 100).toFixed(2)}% done (${formatBytes(
currentLength,
)} / ${formatBytes(totalLength)} MB)`,
)
}
reportProgress()
response.pipe(fileStream)
response.on('data', chunk => {
currentLength += chunk.byteLength
reportProgress()
})
fileStream.on('close', async () => {
await fs_1.promises.rename(downloadFilePath, finalFilePath)
subscriber.complete()
})
})
.on('error', subscriber.error)
})()
})
}
exports.default = downloadFile
function getCachedPath(name) {
return pathUtils.join(cachePath, name)
}
exports.getCachedPath = getCachedPath
exports.default = downloadFile;
function formatBytes(bytes) {
return (bytes / 1000000).toFixed(2)
return (bytes / 1000000).toFixed(2);
}

@@ -21,11 +21,12 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCachedPath = void 0;
const fs = __importStar(require("fs"));
const fs_1 = require("fs");
const fs = __importStar(require("./fs"));
const pathUtils = __importStar(require("path"));
const envPaths = require("env-paths");
const rxjs_1 = require("rxjs");
const followRedirects = require("follow-redirects");
const { https } = followRedirects;
const observe_async_1 = __importDefault(require("./observe-async"));
const download_file_1 = __importDefault(require("./download-file"));
const cachePath = envPaths('apk-mitm', { suffix: '' }).cache;

@@ -39,3 +40,3 @@ function createToolDownloadTask(tool) {

const fileName = `${tool.name}-${tool.version.name}.jar`;
return downloadFile(task, tool.version.downloadUrl, fileName);
return downloadCachedFile(task, tool.version.downloadUrl, fileName);
},

@@ -45,40 +46,15 @@ };

exports.default = createToolDownloadTask;
function downloadFile(task, url, fileName) {
return new rxjs_1.Observable(subscriber => {
(async () => {
const finalFilePath = getCachedPath(fileName);
if (fs.existsSync(finalFilePath)) {
task.skip('Version already downloaded!');
subscriber.complete();
return;
}
// Ensure cache directory exists
await fs_1.promises.mkdir(cachePath, { recursive: true });
// Prevent file corruption by using a temporary file name
const downloadFilePath = finalFilePath + '.dl';
https.get(url, response => {
if (response.statusCode !== 200) {
const error = new Error(`The URL "${url}" returned status code ${response.statusCode}, expected 200.`);
// Cancel download with error
response.destroy(error);
}
const fileStream = fs.createWriteStream(downloadFilePath);
const totalLength = parseInt(response.headers['content-length']);
let currentLength = 0;
const reportProgress = () => {
const percentage = currentLength / totalLength;
subscriber.next(`${(percentage * 100).toFixed(2)}% done (${formatBytes(currentLength)} / ${formatBytes(totalLength)} MB)`);
};
reportProgress();
response.pipe(fileStream);
response.on('data', (chunk) => {
currentLength += chunk.byteLength;
reportProgress();
});
fileStream.on('close', async () => {
await fs_1.promises.rename(downloadFilePath, finalFilePath);
subscriber.complete();
});
}).on('error', error => subscriber.error(error));
})();
function downloadCachedFile(task, url, fileName) {
return observe_async_1.default(async (next) => {
const finalFilePath = getCachedPath(fileName);
if (await fs.exists(finalFilePath)) {
task.skip('Version already downloaded!');
return;
}
// Ensure cache directory exists
await fs.mkdir(cachePath, { recursive: true });
// Prevent file corruption by using a temporary file name
const downloadFilePath = finalFilePath + '.dl';
await download_file_1.default(url, downloadFilePath).forEach(next);
await fs.rename(downloadFilePath, finalFilePath);
});

@@ -90,4 +66,1 @@ }

exports.getCachedPath = getCachedPath;
function formatBytes(bytes) {
return (bytes / 1000000).toFixed(2);
}

@@ -21,31 +21,32 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("../utils/fs"));
const pathUtils = __importStar(require("path"));
const rxjs_1 = require("rxjs");
const observe_async_1 = __importDefault(require("./observe-async"));
function observeProcess(process, logName) {
return new rxjs_1.Observable(subscriber => {
(async () => {
await fs.mkdir('logs', { recursive: true });
const fileName = pathUtils.join('logs', `${logName}.log`);
const failedFileName = pathUtils.join('logs', `${logName}.failed.log`);
const stream = fs.createWriteStream(fileName);
process
.then(() => {
stream.close();
subscriber.complete();
})
.catch(async (error) => {
stream.close();
await fs.rename(fileName, failedFileName);
subscriber.error(error);
});
process.stdout.on('data', (data) => {
subscriber.next(data.toString().trim());
stream.write(data);
});
process.stderr.on('data', (data) => stream.write(data));
})();
return observe_async_1.default(async (next) => {
await fs.mkdir('logs', { recursive: true });
const fileName = pathUtils.join('logs', `${logName}.log`);
const failedFileName = pathUtils.join('logs', `${logName}.failed.log`);
const stream = fs.createWriteStream(fileName);
process.stdout.on('data', (data) => {
next(data.toString().trim());
stream.write(data);
});
process.stderr.on('data', (data) => stream.write(data));
try {
await process;
}
catch (error) {
await fs.rename(fileName, failedFileName);
throw error;
}
finally {
stream.close();
}
});
}
exports.default = observeProcess;

@@ -13,3 +13,3 @@ {

],
"version": "0.9.4",
"version": "0.9.5",
"license": "MIT",

@@ -16,0 +16,0 @@ "scripts": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc