@paa1997/metho 1.0.5 → 1.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paa1997/metho",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Automated recon pipeline: subfinder → gau → filter → katana → findsomething",
5
5
  "type": "module",
6
6
  "bin": {
package/src/server.js CHANGED
@@ -298,7 +298,8 @@ function openFolderDialog() {
298
298
  return new Promise((resolve, reject) => {
299
299
  let cmd;
300
300
  if (process.platform === 'win32') {
301
- cmd = 'powershell -Command "Add-Type -AssemblyName System.Windows.Forms; $f = New-Object System.Windows.Forms.FolderBrowserDialog; $f.Description = \'Select output directory\'; if ($f.ShowDialog() -eq \'OK\') { $f.SelectedPath } else { \'\' }"';
301
+ // Use Shell.Application COM object more reliable than FolderBrowserDialog via CLI
302
+ cmd = 'powershell -NoProfile -Command "$shell = New-Object -ComObject Shell.Application; $folder = $shell.BrowseForFolder(0, \'Select output directory\', 0, 0); if ($folder) { $folder.Self.Path }"';
302
303
  } else if (process.platform === 'darwin') {
303
304
  cmd = "osascript -e 'POSIX path of (choose folder with prompt \"Select output directory\")'";
304
305
  } else {
@@ -1,13 +1,40 @@
1
- import { execSync } from 'child_process';
1
+ import { exec, execSync } from 'child_process';
2
2
  import { existsSync, mkdirSync } from 'fs';
3
3
  import { join } from 'path';
4
4
 
5
5
  const isWin = process.platform === 'win32';
6
6
 
7
+ function execAsync(cmd, options = {}) {
8
+ return new Promise((resolve, reject) => {
9
+ exec(cmd, options, (err, stdout, stderr) => {
10
+ if (err) {
11
+ err.stdout = stdout;
12
+ err.stderr = stderr;
13
+ reject(err);
14
+ } else {
15
+ resolve({ stdout, stderr });
16
+ }
17
+ });
18
+ });
19
+ }
20
+
7
21
  /**
8
22
  * Check if a binary is available on PATH.
9
23
  */
10
- export function isBinaryAvailable(binary) {
24
+ export async function isBinaryAvailable(binary) {
25
+ try {
26
+ const cmd = isWin ? `where ${binary}` : `which ${binary}`;
27
+ await execAsync(cmd, { stdio: 'pipe' });
28
+ return true;
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Synchronous version for quick checks that don't need to yield.
36
+ */
37
+ export function isBinaryAvailableSync(binary) {
11
38
  try {
12
39
  const cmd = isWin ? `where ${binary}` : `which ${binary}`;
13
40
  execSync(cmd, { stdio: 'pipe' });
@@ -20,9 +47,9 @@ export function isBinaryAvailable(binary) {
20
47
  /**
21
48
  * Check if httpx on PATH is ProjectDiscovery's version (not Python's httpx CLI).
22
49
  */
23
- export function isProjectDiscoveryHttpx() {
50
+ export async function isProjectDiscoveryHttpx() {
24
51
  try {
25
- const output = execSync('httpx -version', { stdio: 'pipe', timeout: 5000 }).toString();
52
+ await execAsync('httpx -version', { stdio: 'pipe', timeout: 5000 });
26
53
  return true;
27
54
  } catch (err) {
28
55
  const stderr = err.stderr ? err.stderr.toString() : '';
@@ -42,13 +69,13 @@ export function isProjectDiscoveryHttpx() {
42
69
  * Attempt to install a tool using its install command (globally via go install).
43
70
  * Returns true if install succeeded, false otherwise.
44
71
  */
45
- export function attemptInstall(toolDef, logger) {
72
+ export async function attemptInstall(toolDef, logger) {
46
73
  if (!toolDef.installCmd) {
47
74
  return false;
48
75
  }
49
76
 
50
77
  if (toolDef.installCmd.startsWith('go install')) {
51
- if (!isBinaryAvailable('go')) {
78
+ if (!await isBinaryAvailable('go')) {
52
79
  logger.warn('Go is not installed. Cannot auto-install Go tools.');
53
80
  logger.warn('Install Go from https://go.dev/dl/ and ensure GOPATH/bin is in PATH.');
54
81
  return false;
@@ -57,12 +84,11 @@ export function attemptInstall(toolDef, logger) {
57
84
 
58
85
  logger.info(`Installing ${toolDef.binary}: ${toolDef.installCmd}`);
59
86
  try {
60
- execSync(toolDef.installCmd, {
61
- stdio: 'pipe',
87
+ await execAsync(toolDef.installCmd, {
62
88
  timeout: 120000,
63
89
  env: { ...process.env },
64
90
  });
65
- return isBinaryAvailable(toolDef.binary);
91
+ return await isBinaryAvailable(toolDef.binary);
66
92
  } catch (err) {
67
93
  logger.debug(`Install failed for ${toolDef.binary}: ${err.message}`);
68
94
  return false;
@@ -73,12 +99,12 @@ export function attemptInstall(toolDef, logger) {
73
99
  * Install a Go tool to a local directory instead of GOPATH/bin.
74
100
  * Returns the full path to the installed binary, or null on failure.
75
101
  */
76
- export function installToLocal(toolDef, localBinDir, logger) {
102
+ export async function installToLocal(toolDef, localBinDir, logger) {
77
103
  if (!toolDef.installCmd || !toolDef.installCmd.startsWith('go install')) {
78
104
  return null;
79
105
  }
80
106
 
81
- if (!isBinaryAvailable('go')) {
107
+ if (!await isBinaryAvailable('go')) {
82
108
  logger.warn('Go is not installed. Cannot auto-install Go tools.');
83
109
  logger.warn('Install Go from https://go.dev/dl/ and ensure GOPATH/bin is in PATH.');
84
110
  return null;
@@ -91,8 +117,7 @@ export function installToLocal(toolDef, localBinDir, logger) {
91
117
 
92
118
  logger.info(`Installing ${toolDef.binary} to ${localBinDir}...`);
93
119
  try {
94
- execSync(toolDef.installCmd, {
95
- stdio: 'pipe',
120
+ await execAsync(toolDef.installCmd, {
96
121
  timeout: 120000,
97
122
  env: { ...process.env, GOBIN: localBinDir },
98
123
  });
@@ -48,13 +48,13 @@ export async function ensureTools(config, logger) {
48
48
 
49
49
  logger.debug(`Checking for ${toolName} (${toolDef.binary})...`);
50
50
 
51
- if (isBinaryAvailable(toolDef.binary)) {
51
+ if (await isBinaryAvailable(toolDef.binary)) {
52
52
  // Special check: verify httpx is ProjectDiscovery's, not Python's
53
- if (toolName === 'httpx' && !isProjectDiscoveryHttpx()) {
53
+ if (toolName === 'httpx' && !await isProjectDiscoveryHttpx()) {
54
54
  logger.warn('Found Python\'s httpx on PATH (not ProjectDiscovery\'s)');
55
55
  logger.info('Installing ProjectDiscovery httpx locally to avoid conflict...');
56
56
 
57
- const localPath = installToLocal(toolDef, LOCAL_BIN_DIR, logger);
57
+ const localPath = await installToLocal(toolDef, LOCAL_BIN_DIR, logger);
58
58
  if (localPath) {
59
59
  resolvedPaths[toolName] = localPath;
60
60
  logger.success(`ProjectDiscovery httpx installed at ${localPath}`);
@@ -76,7 +76,7 @@ export async function ensureTools(config, logger) {
76
76
 
77
77
  // Tool not found at all — try global install first
78
78
  logger.warn(`${toolName} not found, installing...`);
79
- const installed = attemptInstall(toolDef, logger);
79
+ const installed = await attemptInstall(toolDef, logger);
80
80
 
81
81
  if (installed) {
82
82
  resolvedPaths[toolName] = toolDef.binary;
@@ -85,7 +85,7 @@ export async function ensureTools(config, logger) {
85
85
  // Try local install as fallback
86
86
  if (toolDef.installCmd && toolDef.installCmd.startsWith('go install')) {
87
87
  logger.info(`Global install failed, trying local install to ${LOCAL_BIN_DIR}...`);
88
- const localPath = installToLocal(toolDef, LOCAL_BIN_DIR, logger);
88
+ const localPath = await installToLocal(toolDef, LOCAL_BIN_DIR, logger);
89
89
  if (localPath) {
90
90
  resolvedPaths[toolName] = localPath;
91
91
  logger.success(`${toolName} installed locally at ${localPath}`);