riciplay 1.8.95 → 1.9.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.
Files changed (2) hide show
  1. package/bin/riciplay +92 -20
  2. package/package.json +2 -2
package/bin/riciplay CHANGED
@@ -5,17 +5,85 @@
5
5
  // python3 -c "from riciplay_cli.main import app; app()"
6
6
  //
7
7
  // The Python package is installed by scripts/postinstall.js (pip install
8
- // riciplay-cli). When the pip console script exists on PATH, exec it
9
- // directly (identical behavior to a native install); otherwise invoke
10
- // the app entry through python3 with argv[0] normalized so the CLI's
11
- // own help/version output stays correct.
8
+ // riciplay-cli). The real console script is resolved through PATH — the same
9
+ // resolution the OS/shell performs — so a venv/pipx install
10
+ // (<venv>/bin/riciplay) is found instead of silently falling back to the
11
+ // system python3. Crucially, this wrapper's own file is explicitly excluded
12
+ // as a candidate: an npm global install puts a symlink to this very script on
13
+ // PATH (/usr/local/bin/riciplay), and matching it re-executed the wrapper
14
+ // forever. Only when no other candidate exists do we fall back to
15
+ // `python3 -m`, which is exactly the case the wrapper must never feed itself.
12
16
 
13
17
  const { spawn } = require('child_process');
14
- const { existsSync } = require('fs');
18
+ const fs = require('fs');
15
19
  const path = require('path');
16
20
  const { EOL } = require('os');
17
21
 
18
- const args = process.argv.slice(2);
22
+ function realpathSafe(p) {
23
+ try {
24
+ return fs.realpathSync(p);
25
+ } catch {
26
+ return path.resolve(p);
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Filesystem identities of this wrapper, so it can never be selected as its
32
+ * own target. Both the symlinked invoke path (process.argv[1]) and the real
33
+ * module path (__filename) are registered: npm's global bin is a symlink to
34
+ * the latter, while a plain copy would match the former.
35
+ */
36
+ function selfIdentities({ filename, argv1 }) {
37
+ const ids = new Set();
38
+ if (filename) {
39
+ ids.add(realpathSafe(filename));
40
+ ids.add(path.resolve(filename));
41
+ }
42
+ if (argv1) {
43
+ ids.add(realpathSafe(argv1));
44
+ ids.add(path.resolve(argv1));
45
+ }
46
+ return ids;
47
+ }
48
+
49
+ /**
50
+ * Resolve the installed `riciplay` console script via PATH.
51
+ *
52
+ * Returns the candidate path, or null when the only match on PATH is this
53
+ * wrapper itself (in which case the caller falls back to `python3 -m`).
54
+ */
55
+ function resolveConsoleScript(options = {}) {
56
+ const platform = options.platform || process.platform;
57
+ const env = options.env || process.env;
58
+ const filename = options.filename || __filename;
59
+ const argv1 = 'argv1' in options ? options.argv1 : process.argv[1];
60
+ const isWin = platform === 'win32';
61
+
62
+ // Windows: pip installs `riciplay.exe`. npm's own shim is a .cmd/.ps1, so
63
+ // searching for the .exe cannot accidentally match the npm shim.
64
+ const name = isWin ? 'riciplay.exe' : 'riciplay';
65
+ const pathEnv = env.PATH || env.Path || '';
66
+ const sep = isWin ? ';' : ':';
67
+ const own = selfIdentities({ filename, argv1 });
68
+
69
+ for (const dir of pathEnv.split(sep)) {
70
+ if (!dir) continue;
71
+ const candidate = path.join(dir, name);
72
+ let st;
73
+ try {
74
+ st = fs.statSync(candidate); // follows symlinks
75
+ } catch {
76
+ continue;
77
+ }
78
+ if (!st.isFile()) continue;
79
+ // Never re-exec this wrapper — by realpath (npm symlink) or by literal
80
+ // path (copied install).
81
+ if (own.has(realpathSafe(candidate)) || own.has(path.resolve(candidate))) continue;
82
+ if (!isWin && (st.mode & 0o111) === 0) continue; // not executable
83
+ return candidate;
84
+ }
85
+ return null;
86
+ }
19
87
 
20
88
  function fail(msg) {
21
89
  process.stderr.write(`Error: ${msg}${EOL}`);
@@ -30,21 +98,25 @@ function run(cmd, argv) {
30
98
  proc.on('close', (code) => process.exit(code ?? 1));
31
99
  }
32
100
 
33
- // Prefer an installed console script (same PATH resolution pip used).
34
- const isWin = process.platform === 'win32';
35
- const exe = isWin ? 'riciplay.exe' : 'riciplay';
36
- for (const dir of ['/usr/local/bin', '/usr/bin', path.join(process.env.HOME || '', '.local', 'bin')]) {
37
- const candidate = path.join(dir, exe);
38
- if (existsSync(candidate)) {
39
- run(candidate, args);
101
+ function main(argv = process.argv.slice(2)) {
102
+ // Prefer an installed console script (same PATH resolution the OS used).
103
+ const candidate = resolveConsoleScript();
104
+ if (candidate) {
105
+ run(candidate, argv);
40
106
  return;
41
107
  }
108
+
109
+ // Module fallback — app() reads sys.argv; normalize argv[0] so usage
110
+ // strings and version output match the real console script.
111
+ run('python3', [
112
+ '-c',
113
+ "import sys; sys.argv[0] = 'riciplay'; from riciplay_cli.main import app; app()",
114
+ ...argv,
115
+ ]);
116
+ }
117
+
118
+ if (require.main === module) {
119
+ main();
42
120
  }
43
121
 
44
- // Module fallback — app() reads sys.argv; normalize argv[0] so usage
45
- // strings and version output match the real console script.
46
- run('python3', [
47
- '-c',
48
- "import sys; sys.argv[0] = 'riciplay'; from riciplay_cli.main import app; app()",
49
- ...args,
50
- ]);
122
+ module.exports = { resolveConsoleScript, selfIdentities, main };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "riciplay",
3
- "version": "1.8.95",
4
- "description": "AI-powered bug bounty reconnaissance and penetration testing agent — browser, proxy interception, recon, and exploit workflows",
3
+ "version": "1.9.0",
4
+ "description": "AI-powered bug bounty reconnaissance and penetration testing agent \u2014 browser, proxy interception, recon, and exploit workflows",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "riciplay": "./bin/riciplay"